{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Installation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To follow our tutorial, ensure you have Python version 3.8 or higher installed on your system.\n", "To install the [qci-client](https://pypi.org/project/qci-client/) run the following command in your terminal:\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```pip install --upgrade \"qci-client<5\"```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This will install the latest version of the qci-client (version 5 or higher).\n", "For a more organized development environment, we recommend using a virtual environment to isolate qci-client dependencies.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**1.0.2 Configure Variables**\n", " Next, setup two environment variables: one for the API's URL and one for your token. The **API URL** tells the client where to connect, and your **API token** is what allows you to access the API. The operating system you are using determines how you should configure environment variables. On Linux, MacOS and other UNIX-like operating systems, you can edit the configuration file appropriate for your shell. For `.bash_profile` or `.zprofile`, for instance add these lines (Replace `` with your actual API token, a long string of letters and numbers):\n", "\n", "
\n",
    "export QCI_API_URL=https://api.qci-prod.com\n",
    "export QCI_TOKEN=<your_secret_token>\n",
    "
\n", "\n", "For Windows, you must open **System Properties** and press the `Environment Variables...` button on the `Advanced` tab.\n", "\n", "\"System" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the environment variables window, click `New...` in the `User Variables` pane.\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create the `QCI_API_URL` and `QCI_TOKEN` variables with the appropriate values.\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once both of these variables are created, restart your shell or application such as VS Code to get the new configuration." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Testing Your Setup\n", "**1.0.1 Import the qci_client Package**\n", "After installing the qci-client, let's verify your connection and authentication to the QCi API.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#This line imports the qci-client library into your Python environment, making its functionalities accessible for use.\n", "import qci_client as qc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**1.0.3 Create a Client Instance**\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# the following line shows how to directly configure QCIClient with variables\n", "# client = qc.QciClient(api_token=, url=\"https://api.qci-prod.com\")\n", "# if you have configured your environment with the same information, this line will worl\n", "client = qc.QciClient()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This line creates a QciClient object, which acts as your interface to the QCi API. The $api_token$ and url arguments configure the client for your specific account. The print statement verifies the token is stored securely within the client object (avoid displaying your actual token!).\n", "\n", "**1.0.4 Verify Authentication**\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(client.get_allocations()[\"allocations\"][\"dirac\"])\n", "# Output: {'metered': True, 'seconds': 600}\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running a small job" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we've created a client instance and gained access to the API, let's proceed with running a small optimization problem on our Dirac-3 device. This exercise will help us become acquainted with the job pipeline.\n", "\n", "First, we'll define the problem we want to solve. We aim to minimize the energy of a Hamiltonian function, which is described by a polynomial in two variables.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The optimization problem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We solve the following problem:\n", "\n", "$$\n", "\\begin{equation*}\n", "\\begin{aligned}\n", "& \\underset{(x_1,x_2) \\in \\mathbb{R}^2}{\\text{minimize}}\n", "& & H(x_1,x_2) = -x_1^2 + 2\\,x_1 x_2 - x_2^2\\\\\n", "& \\text{subject to}\n", "& & x_1 + x_2 = 1, \\; x_1 \\geq 0, x_2 \\geq 0\n", "\\end{aligned}\n", "\\end{equation*}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 1:**: Encode the problem data into a JSON file format so that it is recognized by the API. In this step, we prepare example data representing a small problem aimed at minimizing the polynomial:\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Here we load some example data which represents a very small problem to minimize the\n", "# 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.\n", "poly_indices = [[1, 1], [1, 2], [2, 2]]\n", "poly_coefficients = [-1, 2, -1]\n", "data = [{\"idx\": idx, \"val\": val} for idx, val in zip(poly_indices, poly_coefficients)]\n", "file = {\n", " \"file_name\": \"hello-world\",\n", " \"file_config\": {\n", " \"polynomial\": {\n", " \"num_variables\": 2,\n", " \"min_degree\": 2,\n", " \"max_degree\": 2,\n", " \"data\": data,\n", " }\n", " }\n", "}\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 2**: Upload the JSON file to the API. A unique file identifier (file_id) will be returned in the file_response, allowing for easy referencing of the uploaded data in subsequent tasks. This is useful when running a parameter sweep, for instance.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "file_response = client.upload_file(file=file)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 3**: Prepare a job body using the file_id and other problem and device configuration metadata. This step involves constructing the job body to be submitted to the API, specifying the job type, the Dirac-3 device, and its configuration details.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Build the job body to be submitted to the API.\n", "# This is where the job type and the Dirac-3 device and its configuration are specified.\n", "job_body = client.build_job_body(\n", " job_type='sample-hamiltonian',\n", " job_name='test_hamiltonian_job', # user-defined string, optional\n", " job_tags=['tag1', 'tag2'], # user-defined list of string identifiers, optional\n", " job_params={'device_type': 'dirac-3', 'relaxation_schedule': 1, 'sum_constraint': 1},\n", " polynomial_file_id=file_response['file_id'],\n", ")\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Where:\n", "\n", "**job type**: Specifies the type of job to be performed. In this case, ’sample-hamiltonian’ indicates that the job involves creating a Hamiltonian.\n", "\n", "**job name**: An optional user-defined string that names the job. Here, it’s set to ’test hamiltonian job’.\n", "\n", "**job tags**: An optional list of user-defined string identifiers to tag the job for easier reference and organization. In this example, the tags are [’tag1’, ’tag2’].\n", "\n", "**job params**: A dictionary containing parameters for configuring the job and the device. The keys and values specify that the device type is ’dirac-3’, with a relaxation schedule of 1 and a sum constraint of 1.\n", "\n", "**polynomial file id**: The unique identifier for the uploaded polynomial file, retrieved from the file response ’file id’. This ID links the job to the specific problem data.\n", "\n", "By preparing the job body in this manner, you set up all necessary configurations and metadata required by the API to process the optimization task on the Dirac-3 device.\n", "\n", "**Step 4**: Submit the job body to the API as a job.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Submit the job and await the result.\n", "job_response = client.process_job(job_body=job_body)\n", "assert job_response[\"status\"] == qc.JobStatus.COMPLETED.value\n", "print(\n", " f\"Result [x_1, x_2] = {job_response['results']['solutions'][0]} is \" + \n", " (\"optimal\" if job_response[\"results\"][\"energies\"][0] == -1 else \"suboptimal\") +\n", " f\" with H = {job_response['results']['energies'][0]}\"\n", ")\n", "\n", "# This should output something similar to:\n", "# 2024-05-15 10:59:49 - Dirac allocation balance = 600 s\n", "# 2024-05-15 10:59:49 - Job submitted: job_id='6644ea05d448b017e54f9663'\n", "# 2024-05-15 10:59:49 - QUEUED\n", "# 2024-05-15 10:59:52 - RUNNING\n", "# 2024-05-15 11:00:46 - COMPLETED\n", "# 2024-05-15 11:00:48 - Dirac allocation balance = 598 s\n", "# Result [x_1, x_2] = [1, 0] is optimal with H = -1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This example provides a basic introduction to using the qci-client to run jobs on Dirac systems. To delve deeper into the capabilities of these machines, explore our additional tutorials and documentation\n", "\n", "**Recommended Resources**:\n", "\n", "[Dirac-3 User Guide](https://quantumcomputinginc.com/learn/spec-sheets/dirac-3-users-guide)\n", "\n", "Example Notebooks: [max-cut](https://quantumcomputinginc.com/learn/tutorials-and-use-cases/max-cut-on-dirac), [portfolio optimization](https://quantumcomputinginc.com/learn/tutorials-and-use-cases/portfolio-optimization-on-dirac)\n", "\n", "These resources will help you learn advanced features to discover more complex usage scenarios and optimization techniques. You can experiment with various problem formulations and data structures. Most importantly, understanding best practices and gain insights into efficient use of Dirac systems.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" } }, "nbformat": 4, "nbformat_minor": 2 }