# Get Backends get /backends Retrieve a list of all available backends. # Get a Characterization get /characterizations/{UUID} This endpoint retrieves a characterization. # Get All Backend Characterizations get /characterizations/backends/{backend} This endpoint retrieves an array of all available backend characterizations, with pagination. # Get the Most Recent Backend Characterization get /characterizations/backends/{backend}/current This endpoint retrieves the most recent backend characterization data available. # API Core Concepts This page details some concepts specific to how the API works. There is also a more-general [platform glossary](/glossary) as well as a [quantum-focused glossary on ionq.com](https://ionq.com/resources/glossary). ## Jobs A **job** is the basic unit of work on the IonQ cloud. Whether you're simulating a simple circuit, or submitting a program to run on our world-class hardware, you'll send it along as a job. *** ## Quantum Programs Quantum programs are collections of circuits to be run on a QPU. They are submitted to a job in the `input` parameter. Examples can be found on the [Writing Quantum Programs](/api-reference/v0.3/writing-quantum-programs) *** ## Metadata Updatable resources (such as a [Job](/api-reference/v0.3/jobs)) can store arbitrary metadata for your convenience — we store but ignore it. For example, you could tag different algorithms or projects for later analysis, or if you're building an app, tag jobs submitted by customers with a unique customer ID. You can specify up to 10 keys, with names up to 40 characters long and values up to 40000 characters long. ```json { "metadata": { "custom_key": "a string, maximum 400 chars" }, "input": { ... } } ``` *** ## Authorization API keys are associated with a user and can be created on the [IonQ Quantum Cloud](https://cloud.ionq.com) application. To authenticate, prefix your API Key with `apiKey ` and place it in the `Authorization` request header. For example: ``` Authorization: apiKey {your-api-key} ``` If you're new to managing API keys, [learn more in our guide](/guides/managing-api-keys). *** ## Pagination You can bulk fetch any resource (for example, [list all jobs](#operation/getJobs) you have access to). In addition to any specific query parameters those endpoints may support for filtering, all endpoints returning multiple resources take two parameters for pagination: next and limit. limit tells us how many objects to return; next identifies the next chunk of the iteration. When loading a paginated resource, you'll receive a next key with each page. Pass it to subsequent queries with a `next` querystring to fetch the next batch. ```bash curl -H "Authorization: apiKey ..." "https://api.ionq.co/v0.3/jobs?limit=100&next=dce01d5c-987e-48e8-b2b7-41c24d69d711" { "jobs": [ ... ], "next": "38f525e4-f865-48f6-a996-dab85ba1f7b0" } ``` *** ## HTTP Responses IonQ uses standard HTTP response status codes to indicate the result of a request. ### Success A successful response will have a status code in the `2XX` range. Successful responses are documented above on a per-endpoint basis. ### Bad Request A request that contained invalid input data will have a `400` response status code and response data indicating the invalid items: ```json { "statusCode": 400, "error": "Bad Request", "message": "\"some-parameter\" was invalid.", "validation": { "keys": [ "some-parameter" ], "source": "params" } } ``` ### Unauthorized A request that fails API Authentication will receive a `401`. See API Key for more details. ```json { "statusCode": 401, "error": "Unauthorized Error", "message": "Invalid key provided. See https://docs.ionq.com/#authentication for details, or email support@ionq.co for help." } ``` ### Not Found A request whose resource does not exist will have a `404` response status code and some detail about the missing resource: ```json { "statusCode": 404, "error": "Not Found Error", "message": "Resource not found. See https://docs.ionq.com/ for details, or email support@ionq.co for help." } ``` ### Internal Server Error Any unexpected errors are indicated by the `500` response status code. Internal service outage. Visit [https://status.ionq.co/](https://status.ionq.co/) to track this incident. ```json { "statusCode": 500, "error": "Internal Server Error", "message": "Internal service outage. Visit https://status.ionq.co/ to track this incident." } ``` # v0.3 Error Codes When a request fails, the API will respond with an appropriate 400 or 500 error in the following format in the body of the response: ```javascript { 'error': 'Error Name', 'message': 'A description of the specific error conditions.', 'statusCode': 400 } ``` | Error | Description | | --------------------- | -------------------------------------------------------------------------------------------- | | Bad Request | Generic request error. The message should indicate the specific parameter which was invalid. | | Forbidden | The request failed to authenticate the supplied API key | | Unauthorized | The supplied API key failed authorization for the requested resource | | Not Found | The specified resource does not exist or could not be found. | | Internal Server Error | A service was unexpectedly offline, unavailable, or failed in an unknown manner. | *** ## Job Errors The following errors are specific to the `/job` ([API reference](/api-reference/v0.3/jobs/)) resource: | Error | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | BillingError | Generic error inside of the billing service | | CircuitTooLarge | The circuit has too many unique gates on a single qubit which created an error when converting to pulse waveforms on-system | | CompilationError | Generic failure in our compilation service | | ContractExpiredError | The billing service shows that the contract governing the key being used has expired | | DebiasingError | Unknown execution error when using debiasing (an IonQ-provided error mitigation technique) | | InternalError | An unattributable internal error | | NotEnoughQubits | The backend you are submitting to has fewer qubits than this job requires | | OptimizationError | Generic error in our optimization service | | PreflightError | Generic error during preflight checks. This most often occurs when the input circuit is syntax checked and includes malformed gates, commands, formats, or similar | | QuantumComputerError | Generic failure that occured while the job was being processed on-QPU | | QuotaExhaustedError | The billing system shows that your user, project, or organization has an inadequate credit balance to run this job | | SimulationError | Generic failure in our simulation service | | SimulationTimeout | Timeout error in our compilation service. This is most commonly caused by simulations that are too large for the service to simulate before hitting our runaway process timeout | | SystemCancel | A member of IonQ staff has manually cancelled your job. This most often occurs as a result of a customer request, but can sometimes represent manual resolution of an unknown failure mode | | TooLongPredictedExecutionTime | preflight error of a specific type: the predicted execution time for the circuit was longer than the single-job timeout duration for a given backend | | TooManyControls | The job submitted includes a multi-control gate with more control qubits (7 or more) than the target backend allows | | TooManyGates | Preflight error of a specific type: the job submitted includes more gates per circuit than the target backend allows | | TooManyShots | Preflight error of a specific type: the job submitted requested more shots than the target backend allows | | UnknownBillingError | Unknown error related to but not originating from our billing service. This most often means the service is briefly unavailable for some reason. | | UnsupportedGate | Preflight error of a specific type: the job submitted uses a gate that the target backend does not allow | *** # Introduction Our API uses the [REST](https://en.wikipedia.org/wiki/Representational_State_Transfer) architectural style, which means we provide unsurprising, resource-oriented URLs and take advantage of built-in HTTP response codes, authentication, verbs, and other features. We allow cross-site requests from any domain, and return JSON responses. *** ## Working with APIs While you can work [directly](/guides/direct-api-submission) with our APIs if you'd like, most users will find it more convenient to work through one of the available SDKs. For new users, we tend to recommend [Qiskit](https://github.com/Qiskit/qiskit), and have provided a [getting started guide](/guides/qiskit) for it. *** ## System status We continuously report the status of our APIs and our QPU fleet at [https://status.ionq.co/](https://status.ionq.co/). On that page, you can subscribe for automated updates when we perform maintenance or experience an outage. System status is also displayed within the IonQ Quantum Cloud application on the [Backends](https://cloud.ionq.com/backends) page. # Cancel a Job put /jobs/{UUID}/status/cancel Cancel the execution of a single job by ID. # Cancel many Jobs put /jobs/status/cancel Cancel the execution of many jobs at once by passing a list of jobs. # Create a Job post /jobs To submit a program to be simulated or executed on our quantum hardware, `POST` it to the `jobs` endpoint. # Delete a Job delete /jobs/{UUID} Permanently delete a job from our service. This cannot be undone. # Delete many Jobs delete /jobs Permanently remove many jobs from our platform. This cannot be undone. # Get a specific Job get /jobs/{UUID} Retrieve a specific job by UUID. # Get a Job's output get /jobs/{UUID}/results Retrieve a specific job's results by UUID. # Get Jobs get /jobs **NOTE**: If request filters are provided, this endpoint will limit responses to 1 or more specific jobs based on those filters.

This endpoint retrieves all jobs this API key is authorized to view. # Migrating from old versions ### Breaking changes * Body has been renamed to `input`, and is always a JSON payload. The `format` field in input replaces lang as a means of controlling what kind of input is being run. * Results are no longer served alongside the job body when fetching jobs; now use the results\_url field to fetch. * *(v0.1 only)* **Calibrations** endpoints has been deprecated in favor of [Characterizations](/api-reference/v0.3/characterizations). ### New features * Error mitigation is now controllable via API. Debiasing can improve performance via randomized qubit mappings and intelligent post-processing of noise. * Ability to specify target hardware generation on Job creation. (e.g. `qpu.aria-1`) ## Non-breaking changes * Histogram example expanded to include scientific notation for a JSON numeric value. # Multicircuit Jobs This guide covers everything from setting up a multicircuit job, submitting it to IonQ's backend, and retrieving the results. Jobs contain a circuit to be executed on a QPU, and in the case of *multicircuit* jobs, multiple circuits are being submitted in a single job payload. The advantage of this approach is that it simplifies the submission process, allowing for example, all of the circuits of a gradient calculation to be submitted in a single HTTP request, instead of over hundreds. When submitting work from a local environment with a poor internet connection, this can also help overcome job submissions failing intermittently from network issues. To ensure smooth processing, please format your quantum programs in `ionq.circuit.v0` as demonstrated below. ## Creating a Multicircuit Job Below is a JSON object that describes a multicircuit job for IonQ's simulator. This job includes two distinct circuits: ```json { "target": "simulator", "shots": 1024, "name": "Multicircuit Job Example", "input": { "format": "ionq.circuit.v0", "gateset": "qis", "qubits": 3, "circuits": [ { "name": "Circuit 1", "circuit": [ { "gate": "rz", "targets": [0], "rotation": -0.7853981633974474 }, { "gate": "ry", "targets": [0], "rotation": 3.141592653589793 } ] }, { "name": "Circuit 2", "circuit": [ { "gate": "h", "targets": [1] }, { "gate": "x", "targets": [2], "controls": [1] } ] } ] } } ``` ## Submitting the Job To submit this multicircuit job to IonQ, use the following `curl` command. Make sure to replace `your-api-key` with your actual API key: ```bash curl -X POST "https://api.ionq.co/v0.3/jobs" \ -H "Authorization: apiKey your-api-key" \ -H "Content-Type: application/json" \ -d '{...}' # JSON data from the creation step ``` ### Expected Response You should receive a JSON response containing the job ID and status, similar to this: ```json { "id": "unique-job-id", "status": "ready", "request": 1234567890 } ``` ## Retrieving Job Results Once the job is complete, fetch the results using the job's UUID provided in the job submission response: ```bash curl "https://api.ionq.co/v0.3/jobs/unique-job-id/results" \ -H "Authorization: apiKey your-api-key" ``` ### Result Example ```json { "circuit1-uuid": { "0": 0.5, "6": 0.5 }, "circuit2-uuid": { "1": 1.0 } } ``` Each UUID represents a circuit within your job, and the results show the probability distribution of the qubit measurements. If you are interested in implementing these steps using the Qiskit SDK, check out this detailed [multicircuit guide with Qiskit and IonQ](https://docs.ionq.com/guides/sdks/qiskit#submitting-multiple-circuits-in-a-single-job). # Using native gates with the IonQ API Learn how to use our hardware-native gateset to run a circuit with the IonQ API This guide covers how to use IonQ's native gates via our API. To learn more about what the native gates are and when to use them, refer to our guide on [getting started with native gates](/guides/getting-started-with-native-gates). Building and submitting circuits using IonQ's hardware-native gateset enables you to bypass our compiler and optimizer, providing more control and transparency than the default abstract gateset (though often at the cost of performance and convenience). Before working with native gates, we recommend reviewing our guides on [Getting Started with Native Gates](/guides/getting-started-with-native-gates) and [Writing Quantum Programs](/api-reference/v0.3/writing-quantum-programs). Native gates are also supported in [Qiskit](/sdks/qiskit/native-gates-qiskit), [Cirq](/sdks/cirq/native-gates-cirq), and [PennyLane](/sdks/pennylane/native-gates-pennylane). This is an advanced-level feature. Using the hardware-native gate interface without a thorough understanding of quantum circuits is likely to result in less-optimal circuit structure and worse algorithmic performance overall than using our abstract gate interface. *** ## Native gate JSON specification If you have used our abstract gate specification, the native gate specification should feel quite familiar. Its parameters are slightly different though, and we'll walk through them here. To specify a circuit using native gates, you must do two things: 1. Set the parameter `gateset` to `"native"` inside the circuit body. This is an optional parameter that defaults to `"qis"`, which signifies our abstract gateset based on the general-purpose gates of quantum information science (QIS). 2. Your `circuit` array must only use native gates. These are formatted similar to [QIS gates](/api-reference/v0.3/writing-quantum-programs#supported-gates). The only gates allowed in a native gate circuit are `gpi`, `gpi2`, and either `ms` or `zz` depending on the backend. You cannot mix and match native and abstract gates in the same circuit. Much more detailed information about the native gate definitions can be found in our [native gates guide](/guides/getting-started-with-native-gates#introducing-the-native-gates) ### Parameters Available parameters (depending on gate type) are: * `gate`: a string representation of the gate name. This works just like the abstract gate interface, but you can only use the available native gates: `gpi`, `gpi2`, `ms`, and `zz`. If you submit any other gates in the array, you'll receive an error. * `phase` or `phases`: a number representation of the phase parameter or parameters in the gate. It is represented in *turns*, where one turn is 2π radians. We accept floating point values between -1 and 1 for this parameter. * `angle`: an optional number representation of the angle parameter, available for the MS gate only. This value is also represented in turns and can range from 0 to 0.25 (fully entangling), with 0.25 being the default. * `target` or `targets`: the number index (starting from zero) of the qubit to apply the gate to. For two-qubit gates, use an array of qubit indices labeled `targets` instead. The parameters in the IonQ native gate specification are always defined in *turns*, not in radians. One turn is 2π radians. ### Gates | Gate | Description | Parameters | | ------ | ----------------------------------------------------------------------------------------------------- | --------------------------------------- | | `gpi` | [GPI gate](/guides/getting-started-with-native-gates#gpi) | `phase`, `target` | | `gpi2` | [GPI2 gate](/guides/getting-started-with-native-gates#gpi2) | `phase`, `target` | | `ms` | [Mølmer–Sørensen gate](\(/guides/getting-started-with-native-gates#ms-gates\)) (only on Aria systems) | `phases`, `angle` (optional), `targets` | | `zz` | [ZZ gate](\(/guides/getting-started-with-native-gates#zz-gates\)) (only on Forte systems) | `angle`, `targets` | *** ## Basic example Here's a simple example circuit using native gates with the IonQ API. ```json { "name": "Hello native gates!", "shots": 1024, "target": "simulator", "input": { "gateset": "native", "qubits": 2, "circuit": [ { "gate": "ms", "targets": [0, 1], "phases": [0, 0] }, { "gate": "gpi", "phase": 0, "target": 0 }, { "gate": "gpi2", "phase": 0, "target": 1 } ] } } ``` Like any other [API job](/guides/direct-api-submission), you can save this to a file, like `native_gates_circuit.json`, and submit it: ```bash curl -X POST "https://api.ionq.co/v0.3/jobs" \ -H "Authorization: apiKey $IONQ_API_KEY" \ -H "Content-Type: application/json" \ -d @native_gates_circuit.json ``` *** ## Additional resources * [Direct API submission](/guides/direct-api-submission) * [API reference for POST /jobs](/api-reference/v0.3/jobs/create-a-job) * [Writing quantum programs](/api-reference/v0.3/writing-quantum-programs) * [Getting started with native gates](/guides/getting-started-with-native-gates) * Using native gates with [Qiskit](/sdks/qiskit/native-gates-qiskit), [Cirq](/sdks/cirq/native-gates-cirq), and [PennyLane](/sdks/pennylane/native-gates-pennylane) # Get an Organization’s Report get /report/organizations/{org_id} Get a usage report for the given organization from the start_date and end_date, detailing how much usage went to each QPU during that period. If no start_date or end_date are provided, period defaults to last 30 days until current time. # Writing Quantum Programs For the best results, please submit quantum programs in the `ionq.circuit.v0` format, as demonstrated below. In the compilation and optimization process, your submitted circuit will be converted to an equivalent, optimized circuit expressed in terms of IonQ's native gates, which may involve combining or canceling out some operations. If you wish to guarantee that the quantum computer executes the exact series of operations that you define, please bypass our compiler and submit directly to our native gate interface. For more examples and the full API specification for defining circuits, refer to [the API reference](/api-reference/v0.3/jobs/create-a-job). To write a quantum program using [Qiskit](/guides/sdks/qiskit) or another SDK, refer to our SDK guides. *** ## Bell State We can create a maximally entangled [Bell state](https://en.wikipedia.org/wiki/Bell_state) by applying a Hadamard gate to a single qubit, and applying a controlled-not gate to a second qubit. Half of the time the second qubit will be measured as $|0⟩$, the other half will be measured as $|1⟩$. ```json { "format": "ionq.circuit.v0", "gateset": "qis", // The fields above are optional, as they are the default. "qubits": 2, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "target": 1, "control": 0 } ] } ``` *** ## GHZ State We can create a three qubit [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) by first applying a Hadamard gate to a single qubit, and then using it as the control qubit for a series of controlled-not gates. ```json { "qubits": 4, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, { "gate": "cnot", "control": 0, "target": 3 } ] } ``` *** ## Toffoli gate The [Toffoli gate](https://en.wikipedia.org/wiki/Toffoli_gate), or controlled-controlled-not gate, is a universal reversible logic gate. We can simply apply a cnot to our target qubit, with two control qubits provided via array. ```json { "qubits": 3, "circuit": [ { "gate": "cnot", "target": 0, "controls": [1, 2] } ] } ``` *** ## Supported Gates For actual execution, gates will be compiled into optimal operations for our trapped ion hardware. For convenience, we provide a more expressive gateset for programming. | Gate | Description | | ------ | ---------------------------------------------- | | `x` | Pauli X gate | | `y` | Pauli Y gate | | `z` | Pauli Z gate | | `rx` | X-axis rotation | | `ry` | Y-axis rotation | | `rz` | Z-axis rotation | | `h` | Hadamard gate | | `not` | Convenient alias for Pauli-X gate | | `cnot` | Convenient alias for controlled-not gate | | `s` | S gate | | `si` | Conjugate transpose of S gate | | `t` | T gate | | `ti` | Conjugate transpose of T gate | | `v` | Square root of not gate | | `vi` | Conjugate transpose of square-root-of-not gate | | `swap` | Swaps two qubits | Each operation in a circuit specifies a `gate` and a `target` qubit index (or a list of multiple `targets`). Rotation gates also specify a `rotation` in radians. In addition, any gate can be expressed as a controlled gate by specifying a `control` qubit, or as its multi-controlled variant by specifying a list of up to seven `controls` (for any gate except `swap`). This can often be used to simplify the circuit's description. In general, circuits expressed in fewer QIS gates will be further optimized for runtime, so using multi-controlled variants of gates is recommended. Examples: * Hadamard gate: `{"gate": "h", "target": 0}` * Controlled-not gate: `{"gate": "cnot", "target": 1, "control": 0}` * Toffoli gate (multi-controlled not gate): `{"gate": "cnot", "target": 0, "controls": [1, 2]}` * Rx gate with $\pi/2$ rotation: `{"gate": "rx", "target": 0, "rotation": 1.5708}` * Swap gate: `{"gate": "swap", "targets": [0,1]}` For more examples and the full API specification for defining circuits, refer to [the API reference](/api-reference/v0.3/jobs/create-a-job). ## Native Specification For information about writing quantum programs using IonQ's hardware-native gate set, refer to our guides on [getting started with native gates](/guides/getting-started-with-native-gates) and [using native gates with the IonQ API](/api-reference/v0.3/native-gates-api). *** ## Other Formats (experimental) Support for submitting programs in [QASM/OpenQASM](https://github.com/Qiskit/openqasm/) and [Quipper](https://www.mathstat.dal.ca/~selinger/quipper/) is currently experimental. If you use these languages, we will compile your code to a logically-equivalent representation using our Supported Gates. (For billing purposes, we'll calculate your program's resource requirements **after** it's been compiled this way.) ### OpenQASM ```json { "format": "openqasm", "data": "string" } ``` ### QASM ```json { "format": "qasm", "data": "string" } ``` ### Quipper ```json { "format": "quipper", "data": "string" } ``` *** Is there a language format you'd like to see supported? Drop us a line and let us know. # null # Connecting a SAML Identity Provider Enhance security and simplify user management by authenticating with your SAML-based SSO provider IonQ Quantum Cloud can be integrated with any [SAML 2.0](https://en.wikipedia.org/wiki/SAML_2.0) compatible Single sign-on (SSO) provider, such as Azure Active Directory, Okta, or JumpCloud. By federating IonQ with your Provider, you can easily provide access to anyone in your organization and manage that access centrally. *** ## Before you begin To successfully complete this integration, you'll need: * The ability to create or register a new Application in your Identity system * Your Identity provider's Entity ID, SAML SSO URL, and Public Key certificate. *** ## Configuring Your Identity Provider Your Identity Provider must be configured to recognize IonQ Quantum Cloud as a new application. How this works varies by provider, but typically you'll find an Applications section within your Admin control panel. When you create the new application, you'll set the following: 1. Assertion Consumer Service (ACS) URL: `https://ionq.firebaseapp.com/__/auth/handler` 2. Application Entity ID: `app.ionq.com` Once the App has been added to your system, you'll be able to create access rules for your users. Again, how this is configured varies by provider, but typically App access is set for either specific roles or specific users. *** ## IonQ Configuration Once the App has been added on the Identity Provider side, email the following information to [support@ionq.co](mailto:support@ionq.co): > 1. Identity provider's Entity ID: A URI that identifies the identity provider. > 2. Identity provider's SAML SSO URL: The URL of the identity provider's sign-in page. > 3. Identity provider's public key certificate: The certificate used to validate tokens signed by the identity provider. Once received, our team will configure the provider in our production environment within 2 business days. *** ## Testing and Support Once we've registered your provider with IonQ Quantum Cloud, the IonQ team will get in touch to work with you so you can debug and test the configuration before enabling it on your organization. If you need further assistance, or have any questions about this process, please reach out at [support@ionq.co](mailto:support@ionq.co) or contact the Customer Success manager for your Organization. # Direct API Submissions Learn how to submit jobs directly to the IonQ API Most users will submit jobs and interact with IonQ through an SDK like [Qiskit](/guides/qiskit), but in some instances direct API submission is needed. This guide walks you through the basics of using the IonQ Quantum Cloud to write and run quantum programs: using the Quantum Cloud API to specify a quantum circuit, submitting it as a job, and then accessing the results. ## Before you begin You'll need an account on the [IonQ Quantum Cloud](https://cloud.ionq.com), and you'll need to create an API key. We also have a guide about [setting up and managing your API keys](/guides/managing-api-keys) if you need some help. This guide assumes that you have followed these instructions and have saved your API key as a local environment variable named `IONQ_API_KEY`. *** ## Writing a quantum circuit We'll need to create a quantum circuit to submit as your first job. Let's use a simple [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) using three qubits, first applying a Hadamard gate to a single qubit, and then using it as the control qubit for a series of controlled-not gates on the other two. Diagrammed, a three-qubit GHZ circuit looks like this: ![A visualization of a Greenberger-Horne-Zeilinger (GHZ) state.](https://mintlify.s3-us-west-1.amazonaws.com/ionq/guides/_media/direct-api-submission-ghz-circuit.png) In IonQ's language-agnostic JSON circuit representation, the circuit looks like this: ```json { "input": { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 } ] } } ``` *** ## Submit your quantum circuit as a Job For the purposes of this guide we'll use `curl` on the command line, but in the real world example, you'd likely want to use a [SDK](/guides/qiskit). Alternately you may be using an HTTP request library in Python, Javascript. Now we're ready to submit this circuit as a job. To submit the job, we need to add a few additional parameters to our circuit: the language, the number of shots, where we want the job to run (ex: `simulator` or `qpu.aria-1`) and, optionally, a name for your own reference. For a full list of options that can be passed to this resource check out the API reference for [POST /jobs](/api-reference/v0.3/jobs/create-a-job). In this case, we'll submit a job to the simulator so that we get our results quickly, and we'll use the Aria [noise model](/guides/simulation-with-noise-models): ```json { "name": "Hello many worlds!", "shots": 1024, "target": "simulator", "noise": { "model": "aria-1" }, "input": { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 } ] } } ``` Paste this in your text editor of choice and then save it using a memorable name—something like `ghz-job.json`. Now, we're ready to submit our job to the IonQ Cloud API. To do that, we'll `POST` our JSON job body to the job creation route, with two headers: one for authorization with the API key we created earlier, and one to tell the API that our job body is JSON formatted. Since we want to see something quickly, we'll submit to `"target": "simulator"` for now. ```bash curl -X POST "https://api.ionq.co/v0.3/jobs" \ -H "Authorization: apiKey $IONQ_API_KEY" \ -H "Content-Type: application/json" \ -d @ghz-job.json ``` Which will return something like: ```json { "id": "7135ca98-176f-48c9-8616-8f53ec505028", "status": "ready", "request": 1718302151 } ``` And there it goes! The `id` can now be used to [cancel it](/api-reference/v0.3/jobs/cancel-a-job), [get the status](api-reference/jobs/get-a-specific-job), or [retrieve results](api-reference/jobs/get-a-specific-jobs-output). *** ## Retrieve the job results To retrieve the job, we can now `GET` it at its own resource URL, determined by the job id: ```bash curl "https://api.ionq.co/v0.3/jobs/{your-job-id}" \ -H "Authorization: apiKey $IONQ_API_KEY" ``` Remember to replace `{your-job-id}` with the ID you just got back. This request will return the current status. Since we submitted to the simulator, our job is already `completed`! (Note: If you decided to submit to a QPU, you'll have to wait for your job to work its way through the queue): ```json { "id": "7135ca98-176f-48c9-8616-8f53ec505028", "submitted_by": "65e8b97c521dcf001299126b", "name": "Hello many worlds!", "status": "completed", "target": "simulator", "qubits": 3, "circuits": 1, "results_url": "/v0.3/jobs/7135ca98-176f-48c9-8616-8f53ec505028/results", "gate_counts": { "1q": 1, "2q": 2 }, "cost_usd": 0, "project_id": "428499cb-c392-4ab1-ad8e-c954a1a99ff5", "request": 1718302151, "start": 1718302154, "response": 1718302154, "execution_time": 78, "predicted_execution_time": 8, "shots": 1024, "noise": { "seed": 917721158, "model": "aria-1" }, "error_mitigation": { "debias": false }, "children": [] } ``` ## Retrieving the results Now that the job has completed, we can retrieve the results using the URL provided in the output: ```bash curl "https://api.ionq.co/v0.3/jobs/{your-job-id}/results" \ -H "Authorization: apiKey $IONQ_API_KEY" ``` Which will return a dictionary with the results of the job: ```json { "0": 0.4619140625, "1": 0.017578125, "2": 0.0185546875, "3": 0.0244140625, "4": 0.0185546875, "5": 0.025390625, "6": 0.0107421875, "7": 0.4228515625 } ``` The results request contains the histogram output of the probabilities of each measured state across all 1024 shots. Two things to note here: the output is sparse, that is, it only shows data for outcomes that were actually measured, and the output keys are formatted as big-endian integers, i.e. 0 is 000, 2 is 010, 3 is 011, and so-on, where the leftmost bit is the qubit with index zero from our submitted program. *** ## Additional Resources If you're working on your own tools to interact with the API, the full [API Reference](/api-reference) has details on HTTP verbs and endpoints, expected response formats, and other features not covered in this guide. Additionally, our [best practices page](https://ionq.com/best-practices) provides detailed instructions for getting the most out of our trapped-ion systems, and our support center is always available to help you solve any problems you might run into. # IonQ API Key Management with dotenv Integration Discover how to effortlessly manage IonQ API keys across various projects by leveraging dotenv's automatic loading feature, enhancing security and codebase cleanliness. ## Leveraging dotenv for IonQ API Key Management Storing and managing API keys securely is paramount in software development, especially when dealing with sensitive services like IonQ's quantum computing API. There are a couple of methods for securely storing your IonQ API key where integrations like `qiskit_ionq` can automatically find it: you can [store it locally in an environment variable on your system](/guides/managing-api-keys#storing-keys) as described in our main API key guide, or use dotenv as shown here. This guide introduces a streamlined approach to handle IonQ API keys using dotenv, which automatically loads `.env` files, thus simplifying the management process across different projects. Using dotenv may be easier than using your system's environment variables, depending on your particular setup and preferences. ## Prerequisites Before diving in, ensure you have: * Registered on the [IonQ Quantum Cloud](https://cloud.ionq.com) and generated your API keys. Visit IonQ's [API key management guide](/guides/managing-api-keys) for detailed instructions. * Python 3.11 installed on your computer. Confirm your Python version with `python --version` via command line. To prevent dependency conflicts, consider utilizing an environment manager like [virtualenv](https://virtualenv.pypa.io/en/latest/) or [conda](https://docs.conda.io/en/latest/). ## Step 1: Creating a .env File Navigate to the root directory of your project and create a `.env` file. This file will host your project-specific settings, including the IonQ API key, keeping them secure and easily accessible. ## Step 2: Adding the IonQ API Key to the .env File Open the `.env` file in a text editor and insert your IonQ API key as shown below: ```plaintext IONQ_API_KEY=your_api_key_here ``` Replace `your_api_key_here` with your actual IonQ API key. After saving the file, your key is securely stored and ready for use. Don't forget that sharing the `.env` file that contains your API key would mean sharing access to your IonQ account and resources. If you unintentionally share the file, you can always revoke an API key from the IonQ Cloud Console. ## Step 3: Ensure dotenv Package Installation The IonQ Provider for Qiskit has been designed to check for and automatically load `.env` files. If you haven't already, ensure the `python-dotenv` package is installed in your environment: ```bash pip install python-dotenv ``` ## Step 4: Using the IonQ API Key in Your Project With the `python-dotenv` package installed and your `.env` file configured, the `IonQProvider` is now set to automatically load and use the API key from the `.env` file without any additional code for dotenv loading in your script. With this automatic loading feature, accessing the IonQ API key in your project code is straightforward. Here's an example with the IonQ Provider for Qiskit: ```python from qiskit_ionq import IonQProvider # The IonQProvider automatically looks for the IONQ_API_KEY in your environment provider = IonQProvider() ``` This setup ensures your IonQ API key is automatically detected and utilized, streamlining the development process. ## Conclusion You've successfully learned how to manage IonQ API keys more efficiently using dotenv's automatic loading functionality. This approach not only secures your API keys by keeping them out of your codebase but also simplifies configuration management across multiple projects. For additional information on quantum computing and project management with IonQ, explore the comprehensive [IonQ documentation](https://ionq.com/docs). # Native Gates Getting started with IonQ's hardware-native gateset This is a general guide covering what the native gates are and why you might want to use them. To learn *how* to use these native gates, refer to our native gate guides for the [IonQ API](/api-reference/v0.3/native-gates-api), [Qiskit](/sdks/qiskit/native-gates-qiskit), [Cirq](/sdks/cirq/native-gates-cirq), and [PennyLane](/sdks/pennylane/native-gates-pennylane). The IonQ Quantum Cloud has one of the best—-maybe *the* best—-optimizing compilers in quantum computing. This allows users to focus on the details of their algorithms instead of the details of our quantum system. You can submit quantum circuits using a large, diverse set of quantum gates that allows for maximum flexibility in how to define your problem, and our compilation and optimization stack ensures that your circuit runs on our QPUs in the most compact, streamlined, hardware-optimized form possible. This flexibility in circuit definition also allows for high portability of algorithm code. We don't restrict you to hardware-native basis gates, so you're free to define in any gateset you want—-even the basis gates of a different hardware provider—-and then simply submit to IonQ hardware as-is. No changes necessary! While this is ideal for many applications, the hardware-native basis gateset allows for more customizability, flexibility, and what-you-submit-is-what-you-get control. Being as “close to the metal” as possible allows for control over each individual gate and qubit, unlocking avenues of exploration that are impossible with a compiler between you and the qubits. Currently, submitting circuits defined in native gates is the only way to bypass the compiler and optimizer. Read on to get started with our hardware-native gate specification, learn how it works, and run an example circuit using this powerful new ability. This is an advanced-level feature. Using the hardware-native gate interface without a thorough understanding of quantum circuits is likely to result in less-optimal circuit structure and worse algorithmic performance overall than using our abstract gate interface. *** ## When to use native gates Native gates are not the right solution for every problem. As the warning above states, the native gate specification is an advanced-level feature. If your goal is simply to run a quantum circuit for evaluation or algorithm investigation purposes, using native gates will *often* result in lower-quality output than simply using the abstract gate interface. The native gate interface is the simplest, most direct way to run a circuit on IonQ hardware: we run exactly the gates you submitted, as submitted, and we return the results. That's it. ![Comparison of submitting via the native gate interface (blue) and the abstract interface (black)](https://mintlify.s3-us-west-1.amazonaws.com/ionq/guides/_media/native-gate-flow.png) This means that our proprietary compilation and optimization toolchain is **fully turned off** when we execute a "native" circuit. (Error mitigation is also turned off by default, though you can choose to override this setting and turn on debiasing.) To take full advantage of our compilation, optimization, and error mitigation, you must submit your circuit using our default abstract gate interface, and if you are looking for maximum algorithmic performance from our systems, it is likely that you'll find it by doing just that. But, this toolchain performs a number of transformations on submitted circuits that we consider proprietary, and we therefore do not disclose the full details of how it works. By the time a circuit you submit through the abstract gate interface actually runs on hardware, it has been changed, sometimes considerably. Extraneous gates are optimized away or commuted into different places, they are transpiled into native gates using special heuristics and optimized again, and so on. So, we recommend only using native gates when you cannot use the abstract interface to accomplish your goals - when you need to know exactly what circuit was run, or when you specifically want to run circuits that are not optimized. This might involve investigation and characterization of noise, designing noise-aware circuits, or exploring new error mitigation techniques, as well as the development and testing of circuit optimization and compilation methods. *** ## Introducing the native gates The native gateset is the set of quantum gates that are physically executed on IonQ hardware by addressing ions with resonant lasers via stimulated Raman transitions. We currently expose two single-qubit gates and one two-qubit entangling gate for each QPU. Other native gates may be provided in the future. All gate parameters are measured in *turns* rather than in radians: a value of 1 turn corresponds to 2π radians. We track the phase at the pulse level as units of turns--or, more accurately, as units of how long a turn takes--so, we expose the controls in the same way to you. This reduces floating point conversion error between what you submit and what runs. ### Single-qubit gates The "textbook" way to think about single-qubit gates is as rotations along different axes on the Bloch sphere, but another way to think about them is as rotations along a *fixed* axis while rotating the Bloch sphere itself. Because, in physical reality, the Bloch sphere itself *is* rotating--that is, the phase is advancing in time--changing the orientation of the Bloch sphere is virtually noiseless on hardware. As such, we manipulate qubit states in this "noiseless" phase space whenever possible. #### GPi The GPi gate can be considered a π or bit-flip rotation with an embedded phase. It always *rotates* π radians--hence the name--but can rotate on any longitudinal axis of the Bloch sphere. At a ϕ of 0 turns this is equivalent to an X gate, and at a ϕ of 0.25 turns (π/2 radians) it is equivalent to a Y gate, but it can also be mapped to any other azimuthal angle. $GPI(\phi) = \begin{bmatrix} 0 & e^{-i\phi} \\ e^{i\phi} & 0 \end{bmatrix}$ A single-qubit gate is physically implemented as a Rabi oscillation made with a two-photon Raman transition, i.e. driving the qubits on resonance using a pair of lasers in a Raman configuration. For more details on the physical gate implementation, we recommend [this paper](https://www.nature.com/articles/s41467-019-13534-2) from the IonQ staff. #### GPi2 The GPi2 gate could be considered an RX(π/2)--or RY(π/2)--rotation with an embedded phase. It always *rotates* π/2 radians but can rotate on any longitudinal axis of the Bloch sphere. At a ϕ of 0.5 turns (π radians) this is equivalent to RX(π/2), at a ϕ of 0.25 turns (π/2 radians) it is equivalent to RY(π/2), but it can also be mapped to any other azimuthal angle. $GPI2(\phi)= \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & -ie^{-i\phi} \\ -ie^{i\phi} & 1 \end{bmatrix}$ Like the GPi gate, the GPi2 gate is physically implemented as a Rabi oscillation made with a two-photon Raman transition. #### Virtual Z We do not expose or implement a "true" Z gate (sometimes also called a P or Phase Gate), where we wait for the phase to advance in time, but a Virtual RZ can be performed by simply advancing or retarding the phase of the following operation in the circuit. This does not physically change the internal state of the trapped ion at the time of its implementation; it adjusts the phases of the future operations such that it is equivalent to an actual Z-rotation around the Bloch sphere. In effect, virtual RZ operations are implied by the phase inputs to later gates. $Virtual Z(\theta)= \begin{bmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{bmatrix}$ For example, to add RZ(θ)--an RZ with an arbitrary rotation θ--to a qubit where the subsequent operation is GPi(0.5), we can just add that rotation to the phases of the following gates: > \--RZ(θ)--GPI(0.5)--GPI2(0) = --GPI(θ + 0.5)--GPI2(θ + 0) ### Entangling gates For entangling gates, we offer different options for each QPU: the [Mølmer-Sørenson gate](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.82.1835) on Aria-class systems, and the ZZ gate on our Forte-class systems. #### MS gates Invented in 1999 by [several groups simultaneously](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.59.R2539), the Mølmer-Sørenson gate along with single-qubit gates constitutes a universal gate set. By irradiating any two ions in the chain with a predesigned set of pulses, we can couple the ions' internal states with the chain's normal modes of motion to create entanglement. While it is *possible* to entangle many qubits simultaneously with the Mølmer-Sørenson interaction via global MS, or GMS, we only offer two-qubit MS gates at this time. **Fully entangling MS** The fully entangling MS gate is an XX gate--a simultaneous, entangling π/2 rotation on both qubits. Like our single-qubit gates, they nominally follow the X axis as they occur, but take two phase parameters that make e.g. YY or XY also possible. The first phase parameter ϕ0 refers to the first qubit's phase (measured in turns) as it acts on the second one, the second parameter ϕ1 refers to the second qubit's phase (measured in turns) as it acts on the first one. If both are set to zero, there is no advancing phase between the two qubits because the transition is driven on both qubits simultaneously, in-phase. That is, the *relative* phase between the two qubits remains the same during the operation unless a phase offset is provided. $MS(\phi_0, \phi_1) = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & 0 & 0 & -ie^{-i(\phi_0 + \phi_1)} \\ 0 & 1 & -ie^{-i(\phi_0 - \phi_1)} & 0 \\ 0 & -ie^{i(\phi_0 - \phi_1)} & 1 & 0 \\ -ie^{i(\phi_0 + \phi_1)} & 0 & 0 & 1 \end{bmatrix}$ Note that while two distinct ϕ parameters are provided here (one for each qubit, effectively), they always act on the unitary together. This means that there are multiple ways to get to the same relative phase relationship between the two qubits for this gate; two parameters just makes the recommended approach of "Virtual Z" phase accounting on each qubit across the entire circuit a little neater. **Partially entangling MS** In addition to the fully entangling MS gate described above, we also support partially entangling MS gates, which are useful in some cases. To implement these gates, we add a third (optional) arbitrary angle θ: $\text{MS}(\phi_0,\phi_1,\theta) = \begin{bmatrix} \cos \frac{\theta}{2} & 0 & 0 & -i e^{-i(\phi_0+\phi_1)} \sin \frac{\theta}{2} \\ 0 & \cos \frac{\theta}{2} & -i e^{-i(\phi_0-\phi_1)} \sin \frac{\theta}{2} & 0 \\ 0 & -i e^{i(\phi_0-\phi_1)} \sin \frac{\theta}{2} & \cos \frac{\theta}{2} & 0 \\ -i e^{i(\phi_0+\phi_1)} \sin \frac{\theta}{2} & 0 & 0 & \cos \frac{\theta}{2} \end{bmatrix}$ This parameter is also measured in turns, and can be any floating-point value between 0 (identity) and 0.25 (fully-entangling); in practice, the physical hardware is limited to around three decimal places of precision. Requesting an MS gate without this parameter will always run the fully entangling version. Partially entangling MS gates yield more compact circuits: to produce the same effect as one arbitrary-angle MS gate would require up to two fully-entangling MS gates plus four single-qubit rotations. This offers a potential reduction in gate depth that can indirectly improve performance by removing unnecessary gates in certain circuits. Additionally, small-angle MS gates are generally more performant: for smaller angles, these gates are implemented by lower-power laser pulses, and therefore experience lower light shift and other power-dependent errors. We do not currently have a detailed characterization of how much more performant these gates are on our current-generation systems, but in our (now-decommissioned) system described in [this paper](https://www.nature.com/articles/s41467-019-13534-2), we saw an improvement from \~97.5% to \~99.6% two qubit fidelity when comparing angles of π/2 and π/100, which is described [in more detail here](https://www.nature.com/articles/s41534-020-0259-3). #### ZZ gates Our Forte systems use the ZZ gate, which is another option for creating entanglement between two qubits. Unlike the Mølmer-Sørenson gate, the ZZ gate only requires a single parameter, θ, to set the phase of the entanglement. $ZZ(\theta) = \exp\left(-i \frac{\theta}{2} Z{\otimes}Z\right) = \begin{pmatrix} e^{-i \frac{\theta}{2}} & 0 & 0 & 0 \\ 0 & e^{i \frac{\theta}{2}} & 0 & 0 \\ 0 & 0 & e^{i \frac{\theta}{2}} & 0 \\ 0 & 0 & 0 & e^{-i \frac{\theta}{2}} \end{pmatrix}$ *** ## Converting to native gates You can write a quantum circuit using native gates directly, but you can also convert an abstract-gate circuit into native gates. To do this automatically, we [support Qiskit's transpiler](/sdks/qiskit/native-gates-qiskit#transpiling-a-circuit-to-native-gates). Here, we'll walk through the general approach for manually translating circuits into native gates. Each quantum circuit submitted to the IonQ Cloud must use a consistent gateset throughout--you cannot mix and match native gates and abstract gates in the same circuit. ### General algorithm To translate anything into native gates, the following general approach works well: 1. Decompose the gates used in the circuit so that each gate involves at most two qubits. 2. Convert all easy-to-convert gates into RX, RY, RZ, and CNOT gates. 3. Convert CNOT gates into XX gates using the decomposition described [here](https://arxiv.org/abs/1603.07678) and at the bottom of this section. 4. For hard-to-convert gates, first calculate the matrix representation of the unitary, then use either [KAK decomposition](https://arxiv.org/abs/quant-ph/0507171) or the method introduced in [this paper](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.77.066301) to implement the unitary using RX, RY, RZ and XX. Note that Cirq and Qiskit also have subroutines that can do this automatically, although potentially not optimally. See [cirq.linag.kak\_decomposition](https://quantumai.google/reference/python/cirq/kak_decomposition) and [qiskit.synthesis.TwoQubitBasisDecomposer](https://docs.quantum.ibm.com/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer). 5. Write RX, RY, RZ and XX into GPi, GPi2 and MS gates as documented above (making sure to convert all angles and phases from radians to turns). #### CNOT to XX decomposition A CNOT gate can be expressed in XX, RX, and RY gates which can be directly converted to IonQ's native gates. ```python ----@----- ----| RY(π/2) |----| |----| RX(-π/2) |----| RY(-π/2) |----- | = | XX(π/4) | ----X----- -------------------| |----| RX(-π/2) |--------------------- ``` Many more advanced approaches, decompositions, and optimizations for trapped-ion native gates, including a parameterizable version of this decomposition can be found in [Basic circuit compilation techniques for an ion-trap quantum machine](https://arxiv.org/abs/1603.07678), where this decomposition is described. *** ## Additional resources To learn how to use native gates via the IonQ API and supported SDKs: * [Native gates in the IonQ API](/api-reference/v0.3/native-gates-api) * [Native gates in Qiskit](/sdks/qiskit/native-gates-qiskit) * [Native gates in Cirq](/sdks/cirq/native-gates-cirq) * [Native gates in PennyLane](/sdks/pennylane/native-gates-pennylane) For those interested in learning more about trapped-ion quantum computers as a physical apparatus, the implementation of gates, etc, we recommend [the PhD theses from our cofounder Chris Monroe's lab](https://iontrap.umd.edu/publications/theses/) as a starting point, especially those of Debnath, Egan, Figgat, Landsman, and Wright. The hardware they describe is in many ways the "first iteration" of IonQ's hardware, and much of the fundamental physics of the trapped-ion approach carries over. # Hosted Hybrid Service Run hybrid execution loops using functions managed by IonQ's Cloud. The Hosted Hybrid service is currently in a limited preview and only available to customers with an active contract. Please contact [support@ionq.co](mailto:support@ionq.co) for more information. IonQ's Hosted Hybrid Service allows users to run hybrid quantum-classical workloads without needing to write or host the classical optimization logic. This means that you can run a hybrid algorithm like a VQE, optimize the inputs with a method like SPSA, and do it all without having to write-or-run any of the code yourself. This service introduces a two new things to our platform: A ***Quantum Function*** is an abstraction that represents a composition of classical and quantum logic to perform simple computations. We currently expose two types of Quantum Functions: * **Hamiltonian Energy**, which takes an ansatz and a hamiltonian to perform hamiltonian energy evaluation. * **Quadratically Constrained Quadratic Program** that models the objective of a (constrained) quadratic program. This `QuantumFunction` can be used to solve constrained quadratic programs. An ***Optimization*** looks for the optimal parameters for a Quantum Function using a supported optimization function. Once completed, the solution returned is the minimum energy value and the optimal parameters used to achieve it. These new tools allow you take a problem that you want to solve, represent it in the form of a function, and run it through an optimization routine—without having to run any of the classical code yourself in a local notebook, or manage a remote execution environment. *** ## Setup To run hybrid workloads with this tool, you'll need: We recommend using a version manager such as [pyenv](https://github.com/pyenv/pyenv) or [asdf](https://asdf-vm.com/guide/introduction.html) to simplify management and upgrades. ```bash pip install 'ionq[all]' ``` We'll start by setting up our our `Client` which will allow us to connect to IonQ's platform, then select a backend to use with it. ```python # Initialize backend from ionq.client import Client from ionq import Backend # Initialize a client for connecting to the IonQ API client = Client() # Note: Assuming it's stored as $IONQ_API_KEY in your environment, # the SDK (and any other quantum SDK) will find it automatically. # However, if you wanted to specify it directly, you could with: # client = Client(api_key="aaa-bbb-ccc") # Select a backend to use. We'll stick with the simulator for now, but you can backend = Backend(name="simulator", client=client) ``` *** ## Creating a demo workload In practice, you'd be using our hamiltonian energy evaluations to evaluate *your own* hamiltonians and ansatze, but for this guide we'll build a couple of functions for creating random inputs -- but if you can provide your own, more the better. So first, we'll build an example hamiltonian: ```python import random import math from itertools import product from qiskit.quantum_info import SparsePauliOp # Create our example hamiltonian num_qubits = 2 # or more, but it scales rapidly! pauli_list = [ (ps, random.uniform(-1, 1)) for ps in [ "".join(p) for p in list(product(["I", "X", "Y", "Z"], repeat=num_qubits)) ] ] # Create and display an example hamiltonian hamiltonian = SparsePauliOp.from_list(pauli_list) ``` Which, if we `print`ed it, would look something like: > ```python > print(hamiltonian.to_matrix()) > > [[-0.66819263+0.j -1.36722223-1.22394246j 1.61219673+1.45550222j > 0.1523982 -1.25363417j] > [-1.36722223+1.22394246j 1.40731579+0.j -1.42421166+0.51092863j > -0.16465104-0.43298482j] > [ 1.61219673-1.45550222j -1.42421166-0.51092863j 0.86269394+0.j > -0.388201 -0.74335051j] > [ 0.1523982 +1.25363417j -0.16465104+0.43298482j -0.388201 +0.74335051j > 2.28670504+0.j ]] > ``` Now we'll do the same for an example ansatz and some initial parameters: ```python from qiskit import QuantumCircuit from qiskit.circuit import Parameter params = [Parameter(f"θ{i}") for i in range(2 * num_qubits)] ansatz = QuantumCircuit(num_qubits) # Add a layer of single-qubit parameterized rotations (Ry and Rz) for i in range(num_qubits): ansatz.ry(params[i], i) ansatz.rz(params[i + num_qubits], i) ansatz.barrier() # Add CNOT gates to entangle the qubits for i in range(num_qubits - 1): ansatz.cx(i, i + 1) # Set up some initial parameters initial_params = { params[i]: random.uniform(0, 2 * math.pi) for i in range(2 * num_qubits) } ``` Which will produce an ansatz that looks something like: > ```python > ansatz.draw(output="mpl") > ``` > > ![Image](https://mintlify.s3-us-west-1.amazonaws.com/ionq/guides/_media/hosted_hybrid-example_ansatz.png) *** ## Example 1: Running a simple circuit As a simple demonstration of functionality, let's take our backend and submit a basic circuit job to it using our example ansatz. This is *not* a hybrid workflow, but a normal circuit job. Note: We're using `ionq.ionq_qiskit`, which is a helper library we are providing for translating Qiskit circuits into IonQ-native QIS. ```python from ionq.utils import ionq_qiskit # Create a circuit using a helper that translates Qiskit circuits to QIS circuit = ionq_qiskit.to_circuit( [ansatz.assign_parameters(initial_params, inplace=False)] ) # And submit it to our backend circuit_job = backend.run( circuit, name="Example 1: Circuit Workload" ) ``` And plotting this circuit we'll see something like: > ```python > circuit_results = circuit_job.results() > for results in circuit_results: > results.plot_results() > ``` > > ![Circuit Workload Histogram](https://mintlify.s3-us-west-1.amazonaws.com/ionq/guides/_media/hosted_hybrid-circuit_workload_histogram.png) *** ## Example 2: Running a Quantum Function Now we're build on this by submitting a *`QuantumFunction`* instead of just a simple circuit. A quantum function is a workload that has some predefined logic built in to it. In this case, we'll pass it an ansatz and a hamiltonian, and when we send it to the backend along with a set of parameters, it will submit circuits and do an Hamiltonian Energy evaluation. ```python from ionq.jobs import HamiltonianEnergy from ionq.utils import ionq_qiskit # Build a QuantumFunction qfunc = HamiltonianEnergy( ansatz=ionq_qiskit.to_ansatz(ansatz), hamiltonian=ionq_qiskit.to_hamiltonian(hamiltonian), ) # Submit it to the backend qfunc_job = backend.run( qfunc, params=list(initial_params.values()), name="Example 2: Quantum Function Workload", ) ``` *** ## Example 3: Quadratically Constrained Quadratic Program Objective We can also prepare the model for a constrained quadratic program, by creating a Quantum Function that takes an ansatz, a QUBO matrix, and a list of constraints. This can then be used to solve constrained quadratic programs with classical optimization methods. Let's first model it, with some simple linear constraints and confirm it runs with a random set of parameters. ```python import numpy as np from ionq.problems.quadratic import LinearConstraint from ionq.problems import QCQPObjective from ionq.utils import ionq_qiskit Q = np.array([[4, -6], [-6, 10]]) constraints = [ LinearConstraint( coeffs=[1, 2], rhs=5, ), LinearConstraint( coeffs=[3, 4], rhs=6, ) ] print(f"{Q=}", "\n\n", f"{constraints=}") # Build our QuantumFunction qfunc = QCQPObjective( ansatz=ionq_qiskit.to_ansatz(ansatz), qp_objective=Q, linear_constraints=constraints, penalty=random.uniform(-1, 1), ) # Submit it to the backend qfunc_job = backend.run( qfunc, params=list(initial_params.values()), name="Example 3: Quantum Function (with constraints and a penalty)", ) ``` *** ## Example 4: Optimizations We can also run a (IonQ hosted!) classical loop to optimize our parameters. Here we'll take the same quantum function we ran in Example 3, but we'll add a 5-iteration optimization using SPSA. It doesn't add that much complexity here, only requiring some simple additions: 1. What `method` to use for optimization 2. The maximum desired number of iterations 3. The learning rate, and perturbation for each iteration These values will define how each iteration in the series will change based on the results of the previous job. ```python from ionq.jobs import Optimization from ionq.jobs import OptimizationMethod opt = Optimization( quantum_function=qfunc, method=OptimizationMethod.SPSA, initial_params=list(initial_params.values()), log_interval=1, options={"maxiter": 5, "learning_rate": 0.1, "perturbation": 0.5}, maxiter=5, ) # Run the optimization job opt_job = backend.run( opt, name="Example 4: Optimization" ) ``` As before, we've provided some useful helpers for visualization. running `plot_results()` gives us: > ```python > opt_results = opt_job.results() > opt_results.plot_results() > ``` > > ![A graph of the results of an optimization job.](https://mintlify.s3-us-west-1.amazonaws.com/ionq/guides/_media/hosted_hybrid-opt_job_results.png) And retrieving the "results" of this job will identify the `minimum_value` and `optimal_parameters` for the problem: > ```python > "solution": { > "minimum_value": -0.6128005853629444, > "optimal_parameters": [ > 4.915170460439439, > 3.228145593574783, > 5.550801246532398, > -0.012326729967622713 > ] > } > ``` *** ## Learn more This service is still in a private alpha at this time, but reach out to [sales@ionq.co](mailto:sales@ionq.co) for more information, or contact your account manager. # Managing API keys Learn how to create and manage your IonQ API keys for secure access through SDKs and APIs. An **API key** is similar to a password—it's a string of text used to authenticate (identify yourself) with to our systems and allow the system to authorize that you have access to the action you're attempting to take. When using our APIs IonQ uses API keys to manage access to our systems. Users must provide a valid key when using APIs both directly or through an SDK. ## Creating API keys API keys are created in the [IonQ Quantum Cloud](https://cloud.ionq.com/settings/keys) application under the API Keys page found in the top menu (pictured above.) On that page, you can also see a list of currently active keys, see when they were last used, and revoke (delete) any that are no longer needed.