Quick start on cloud

Device: Dirac-3

Qatalyst overview

Qatalyst is a software package from Quantum Computing Inc. It provides a REST API, which can be programmed in any programming language.

The remainder of this document will walk the user through the steps necessary to obtain an access token (API token), test that the token works, and run a small problem. We will use the qci-client written in Python.

Obtaining an Access Token

To run jobs using the qci-client you will need an active account and an API token from QCI. To request a QCI user account and a token, submit below and wait for a response:

Setting up and testing your token

Once you have an API token you can perform the following steps to confirm that you have connectivity.

Installing the client

First, we'll install qci-client package which requires Python 3.8 or higher. Once you have a suitable virtual environment with Python 3.8+ set up, from within that environment execute this command:

pip install --upgrade "qci-client<5"

Testing your setup

With qci-client installed you should be able to authenticate to the API with your token. To test, let's confirm that we can authenticate. First, import the package:

import qci_client as qc

Next, set a couple of variables:

api_url = "https://api.qci-prod.com"
api_token = "<your_secret_token>"

Now you can instantiate the client and check that it knows your API token:

client = qc.QciClient(api_token=api_token, url=api_url)
print(client.api_token)
# <your_secret_token>

Finally, check that you can authenticate successfully to API by checking your Dirac devices allocation. For metered accounts, this must be a positive number of seconds in order to run jobs:

print(client.get_allocations()["allocations"]["dirac"])
# {'metered': True, 'seconds': 600}

Running a small job

To get familiar with the job pipeline, let's run a job on the Dirac-3 machine to solve a small optimization problem.

We'll walk through the steps to minimize the energy of a so-called Hamiltonian function defined by a polynomial in 2 variables.

The optimization problem

We solve the following problem:

minimize(x1,x2)H(x1,x2)=x12+2x1x2x22subject tox1+x2=1,  x10,x20 \begin{equation*} \begin{aligned} & \underset{(x_1,x_2)}{\text{minimize}} & & H(x_1,x_2) = -x_1^2 + 2\,x_1 x_2 - x_2^2\\ & \text{subject to} & & x_1 + x_2 = 1, \; x_1 \geq 0, x_2 \geq 0 \end{aligned} \end{equation*}

Main stages of a job

1) Encode the problem data into a file that is recognized by the API.

2) Upload the file to the API. A unique file_id will be returned. Once uploaded, the same data can be referenced multiple times. This is useful when running a parameter sweep, for instance.

3) Prepare a job_body using the file_id and other problem and device configuration metadata.

4) Submit the job_body as a job to the API. The job is given a unique job_id. In this example, we wait synchronously for the results as the job moves through the pipeline.

# Insert your API token below, and this script should run as a standalone Python script.
import qci_client as qc
client = qc.QciClient(
url="https://api.qci-prod.com",
api_token="<your_secret_token>",
)
# Stage 1:
# Here we load some example data which represents a very small problem to minimize the
# polynomial H = -x_1^2 + 2*x_1*x_2 - x_2^2, subject to x_1 + x_2 = 1, x_1>=0, x_2>=0.
poly_indices = [[1, 1], [1, 2], [2, 2]]
poly_coefficients = [-1, 1, -1]
data = [{"idx": idx, "val": val} for idx, val in zip(poly_indices, poly_coefficients)]
file = {
"file_name": "hello-world",
"file_config": {
"polynomial": {
"num_variables": 2,
"min_degree": 2,
"max_degree": 2,
"data": data,
}
}
}
# Stage 2:
# Upload the file. A file_id is returned in the file_response.
file_response = client.upload_file(file=file)
# Stage 3:
# Build the job body to be submitted to the API.
# This is where the job type and the Dirac-3 device and its configuration are specified.
job_body = client.build_job_body(
job_type='sample-hamiltonian',
job_name='test_hamiltonian_job', # user-defined string, optional
job_tags=['tag1', 'tag2'], # user-defined list of string identifiers, optional
job_params={'device_type': 'dirac-3', 'relaxation_schedule': 1, 'sum_constraint': 1},
polynomial_file_id=file_response['file_id'],
)
# Stage 4:
# Submit the job and await the result.
job_response = client.process_job(job_body=job_body)
assert job_response["status"] == qc.JobStatus.COMPLETED.value
print(
f"Result [x_1, x_2] = {job_response['results']['solutions'][0]} is " +
("optimal" if job_response["results"]["energies"][0] == -1 else "suboptimal") +
f" with H = {job_response['results']['energies'][0]}"
)
# This should output something similar to:
# 2024-05-15 10:59:49 - Dirac allocation balance = 600 s
# 2024-05-15 10:59:49 - Job submitted: job_id='6644ea05d448b017e54f9663'
# 2024-05-15 10:59:49 - QUEUED
# 2024-05-15 10:59:52 - RUNNING
# 2024-05-15 11:00:46 - COMPLETED
# 2024-05-15 11:00:48 - Dirac allocation balance = 598 s
# Result [x_1, x_2] = [1, 0] is optimal with H = -1

This simple example is enough to get you started on running jobs on Dirac systems with QciClient. If you are ready to continue the journey through using Dirac systems, try out these tutorials.