diff --git a/.github/workflows/test_notebooks.yml b/.github/workflows/test_notebooks.yml index c1e54db..b0c6e07 100644 --- a/.github/workflows/test_notebooks.yml +++ b/.github/workflows/test_notebooks.yml @@ -9,35 +9,137 @@ on: - main jobs: + discover: + name: Discover notebooks + runs-on: ubuntu-22.04 + outputs: + notebooks: ${{ steps.find-notebooks.outputs.notebooks }} + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Find all notebooks + id: find-notebooks + run: | + echo "==================================================" + echo "Discovering notebooks" + echo "==================================================" + notebooks=$(find . -name "*.ipynb" -type f -not -path "*/venv/*" | jq -R -s -c 'split("\n")[:-1]') + echo "Found notebooks:" + echo "$notebooks" | jq -r '.[]' + echo "notebooks=$notebooks" >> $GITHUB_OUTPUT + test: + name: Test ${{ matrix.notebook }} + needs: discover runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + notebook: ${{ fromJson(needs.discover.outputs.notebooks) }} steps: - name: Check out code uses: actions/checkout@v4 - - name: Set up Conda - uses: conda-incubator/setup-miniconda@v2 + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + + - name: Set up Python + uses: actions/setup-python@v5 with: - activate-environment: myenv - environment-file: environment.yml python-version: "3.11" - auto-activate-base: false - - name: Prepare Conda environment - shell: bash -l {0} + - name: Install dependencies with uv run: | - if conda env list | grep -q 'myenv'; then - echo "Environment 'myenv' already exists, updating environment" - conda env update --name myenv --file environment.yml --prune + echo "==================================================" + echo "Installing dependencies for ${{ matrix.notebook }}" + echo "==================================================" + start_time=$(date +%s) + + uv pip install --system -e . + + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + echo "✓ Dependencies installed in ${elapsed}s" + + - name: Verify environment + run: | + echo "==================================================" + echo "Verifying environment setup" + echo "==================================================" + echo "✓ Python version:" + python --version + echo "" + echo "✓ uv version:" + uv --version + echo "" + echo "✓ Installed packages:" + uv pip list | grep -E "(jupyter|qiskit|cirq|pennylane|qbraid|cudaq)" || echo " (packages installed)" + echo "" + echo "✓ IONQ_API_KEY status:" + if [ -n "$IONQ_API_KEY" ]; then + echo " API key is set (length: ${#IONQ_API_KEY} characters)" else - echo "Creating new environment 'myenv'" - conda env create -f environment.yml + echo " WARNING: API key is not set!" fi + env: + IONQ_API_KEY: ${{ secrets.IONQ_API_KEY }} - - name: Run notebook tests - shell: bash -l {0} + - name: Execute notebook run: | - conda activate myenv - python tests/test_notebooks.py + echo "==================================================" + echo "Executing: ${{ matrix.notebook }}" + echo "Timeout: 600s" + echo "==================================================" + start_time=$(date +%s) + echo "Starting execution at $(date '+%Y-%m-%d %H:%M:%S')" + + python -m jupyter nbconvert \ + --to html \ + --execute \ + --ExecutePreprocessor.timeout=600 \ + "${{ matrix.notebook }}" + + exit_code=$? + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + + if [ $exit_code -eq 0 ]; then + echo "✓ PASSED in ${elapsed}s" + echo "Completed at $(date '+%Y-%m-%d %H:%M:%S')" + else + echo "✗ FAILED after ${elapsed}s" + exit $exit_code + fi env: IONQ_API_KEY: ${{ secrets.IONQ_API_KEY }} + + - name: Upload execution artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: notebook-output-${{ hashFiles(matrix.notebook) }} + path: | + **/*.html + retention-days: 7 + + summary: + name: Test Summary + needs: test + runs-on: ubuntu-22.04 + if: always() + steps: + - name: Summary + run: | + echo "==================================================" + echo "Test Execution Complete" + echo "==================================================" + if [ "${{ needs.test.result }}" == "success" ]; then + echo "✓ All notebook tests passed successfully!" + else + echo "✗ Some tests failed. Check individual job logs for details." + exit 1 + fi diff --git a/.gitignore b/.gitignore index 2735e82..f5d5b2e 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ share/python-wheels/ .Python env/ venv/ +.venv/ ionq/ build/ develop-eggs/ diff --git a/README.md b/README.md index fc1c7e9..e1a4831 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,32 @@ There are a wide variety of ways to run these notebooks, but for starters you'll 1. [Python](https://www.python.org/downloads/) installed, using a version between 3.8 and 3.11. 2. A [virtual environment](https://docs.python.org/3/library/venv.html) to help ensure your dependencies don't conflict with anything else you have installed. 3. An [IonQ API key](https://cloud.ionq.com/settings/keys), which optionally you can store as an environment variable for ease of use. Our notebooks expect to find it stored as `IONQ_API_KEY`. -4. An installation of the library you're wanting to run. To install all the libraries at once using Conda, run the following command from the root directory of this repository: +4. An installation of the library you're wanting to run. You can install all libraries using one of the following methods: + + **Option 1: Using uv (Fastest - Recommended)** + + [uv](https://github.com/astral-sh/uv) is an extremely fast Python package installer and resolver: + + ```shell + # Install uv (if not already installed) + curl -LsSf https://astral.sh/uv/install.sh | sh + + # Install all dependencies + uv pip install -e . + ``` + + **Option 2: Using Conda** ```shell conda env create -f environment.yml ``` + **Option 3: Using pip** + + ```shell + pip install -e . + ``` + --- ## Usage diff --git a/api.ipynb b/api.ipynb index 1dee71d..8a6a889 100644 --- a/api.ipynb +++ b/api.ipynb @@ -13,83 +13,24 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "import json, os, requests, time\n", - "from getpass import getpass\n", - "\n", - "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", - "\n", - "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", - "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", - "\n", - "api_key = os.getenv('IONQ_API_KEY') or getpass('Enter your IonQ API key: ')" - ] + "source": "import json\nimport time\n\nimport requests\n\nfrom helpers import get_ionq_api_key\n\n# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n\n# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n# should find it. Otherwise you'll be prompted to enter your API key manually.\n\napi_key = get_ionq_api_key()" }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "def submit_job(headers, data):\n", - " url = \"https://api.ionq.co/v0.3/jobs\"\n", - " response = requests.post(url, headers=headers, data=data)\n", - " response_json = response.json()\n", - " assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n", - " return response_json[\"id\"]\n", - "\n", - "def query_job(job_id, headers):\n", - " url = f\"https://api.ionq.co/v0.3/jobs/{job_id}\"\n", - " response = requests.get(url, headers=headers)\n", - " response_json = response.json()\n", - " assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n", - " return response_json[\"status\"]\n", - "\n", - "def get_job_results(job_id, headers):\n", - " url = f\"https://api.ionq.co/v0.3/jobs/{job_id}/results\"\n", - " response = requests.get(url, headers=headers)\n", - " response_json = response.json()\n", - " assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n", - " return response_json" - ] + "source": "# Define helper functions for interacting with IonQ's API.\n\ndef submit_job(headers, data):\n \"\"\"Submit a quantum job to IonQ's API.\"\"\"\n url = \"https://api.ionq.co/v0.3/jobs\"\n response = requests.post(url, headers=headers, data=data)\n response_json = response.json()\n assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n return response_json[\"id\"]\n\ndef query_job(job_id, headers):\n \"\"\"Query the status of a submitted job.\"\"\"\n url = f\"https://api.ionq.co/v0.3/jobs/{job_id}\"\n response = requests.get(url, headers=headers)\n response_json = response.json()\n assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n return response_json[\"status\"]\n\ndef get_job_results(job_id, headers):\n \"\"\"Retrieve the results of a completed job.\"\"\"\n url = f\"https://api.ionq.co/v0.3/jobs/{job_id}/results\"\n response = requests.get(url, headers=headers)\n response_json = response.json()\n assert response.status_code == 200, f\"Error: {response_json.get('message', 'Unknown error')}\"\n return response_json" }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "headers = {\n", - " \"Authorization\": f\"apiKey {api_key}\",\n", - " \"Content-Type\": \"application/json\",\n", - "}\n", - "\n", - "data = {\n", - " \"name\": \"API Example Circuit\",\n", - " \"shots\": 100,\n", - " \"target\": \"simulator\",\n", - " \"input\": {\n", - " \"format\": \"ionq.circuit.v0\",\n", - " \"gateset\": \"qis\",\n", - " \"qubits\": 2,\n", - " \"circuit\": [\n", - " {\n", - " \"gate\": \"h\",\n", - " \"target\": 0\n", - " },\n", - " {\n", - " \"gate\": \"cnot\",\n", - " \"control\": 0,\n", - " \"target\": 1\n", - " }\n", - " ]\n", - " }\n", - "}\n", - "\n" - ] + "source": "# Set up the request headers and define our circuit.\n# This circuit creates a Bell state with two qubits using IonQ's native format.\n\nheaders = {\n \"Authorization\": f\"apiKey {api_key}\",\n \"Content-Type\": \"application/json\",\n}\n\ndata = {\n \"name\": \"API Example Circuit\",\n \"shots\": 100,\n \"target\": \"simulator\",\n \"input\": {\n \"format\": \"ionq.circuit.v0\",\n \"gateset\": \"qis\",\n \"qubits\": 2,\n \"circuit\": [\n {\n \"gate\": \"h\",\n \"target\": 0\n },\n {\n \"gate\": \"cnot\",\n \"control\": 0,\n \"target\": 1\n }\n ]\n }\n}\n" }, { "cell_type": "markdown", @@ -121,34 +62,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'0': 0.5, '3': 0.5}\n" - ] - } - ], - "source": [ - "# Now we'll send the job to our backend for processing.\n", - "\n", - "job_id = submit_job(headers, json.dumps(data))\n", - "\n", - "# And wait for the job to be run.\n", - "\n", - "status = \"ready\"\n", - "while status != \"completed\":\n", - " time.sleep(1) # wait for 1 second before querying again\n", - " status = query_job(job_id, headers)\n", - "\n", - "# And once the job has run, we can plot the results.\n", - "\n", - "results = get_job_results(job_id, headers)\n", - "print(results)" - ] + "outputs": [], + "source": "# Now we'll send the job to our backend for processing.\n\njob_id = submit_job(headers, json.dumps(data))\n\n# And wait for the job to complete.\n\nstatus = \"ready\"\nwhile status != \"completed\":\n time.sleep(1) # Wait for 1 second before querying again.\n status = query_job(job_id, headers)\n\n# Once the job has completed, we can retrieve and display the results.\n\nresults = get_job_results(job_id, headers)\nprint(results)" }, { "cell_type": "markdown", @@ -162,7 +79,7 @@ ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "venv (3.14.2)", "language": "python", "name": "python3" }, @@ -176,10 +93,10 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.14.2" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cirq.ipynb b/cirq.ipynb index daafb5d..b60afec 100644 --- a/cirq.ipynb +++ b/cirq.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -28,26 +28,14 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "import cirq, cirq_ionq, matplotlib.pyplot as plt, os\n", - "from getpass import getpass\n", - "\n", - "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", - "\n", - "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", - "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", - "\n", - "api_key = os.getenv('IONQ_API_KEY') or getpass('Enter your IonQ API key: ')\n", - "\n", - "service = cirq_ionq.Service(api_key=api_key, default_target='simulator')" - ] + "source": "import cirq\nimport cirq_ionq\nimport matplotlib.pyplot as plt\n\nfrom helpers import get_ionq_api_key\n\n# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n\n# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n# should find it. Otherwise you'll be prompted to enter your API key manually.\n\napi_key = get_ionq_api_key()\n\nservice = cirq_ionq.Service(api_key=api_key, default_target='simulator')" }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -64,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -87,28 +75,18 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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yMhIDR48WP7+/lq6dKnq168v6Y8jAV9++aXuvPNOHTt2TIcPH9bhw4d15MgRxcfHa9euXfarnEJCQrR9+3bt2rXLnT+S3eTJk5Wenq42bdpoxYoVmjBhgmJiYtS2bVv99NNPlZrDz8/P/ueioiIdPnxYnTt3lmVZ2rp16wUfv2DBAgUHB6t379721+7w4cOKiYlRQECAVq9eXakcH330kT7//PNyt/Dw8As+NiQkRBs3btShQ4cq9Vx/9umnnyoiIkJDhgyxj3l5eWnUqFE6fvy4MjIyJEnLly+Xl5eXHnroIft+Hh4eSkpKOufcw4cPLzfm7Ov94IMP2v8cEhKia6+9Vv7+/g7ru6699lqFhIToP//5TyV/aqBqcWoJcKG0tDRdc801Kigo0DvvvKO1a9fKx8fHvn337t2yLEtPP/20nn766QrnyMvLU7169TRlyhT1799f11xzjVq2bKmbb75Zf//739WqVavL9eOUM2TIEA0ZMkSFhYXauHGj5syZo/T0dPXr108//PDDBRfG7tu3T88884yWLl1abk1LQUHBBZ9/165dKigosK/J+W+VXXTcrVs3++m0P6vMwt5p06YpISFBkZGRiomJ0S233KL7779fjRs3vuBjf/31VzVr1kweHo6/QzZv3ty+/ex/69SpYz9FdFbTpk0rnNfT09Nelv/Mmdfb19e33KnF4OBg1a9f32GN0tnxqlqTBDiLIgO4UIcOHexXLQ0YMEBdunTRPffco507dyogIMC+BmPs2LGKj4+vcI6z/1h169ZNe/bs0ZIlS7Ry5Ur97//+r2bMmKGZM2faf3O22WyyLKvcHKWlpVXx49kFBQWpd+/e6t27t7y8vPTuu+9q48aN6t69+zkfU1paqt69e+v333/Xk08+qejoaPn7++vgwYMaOnRopdanlJWVKSwsTB988EGF28+1xseV7rzzTnXt2lWLFi3SypUr9eKLL+qFF17Qv//9b/Xt27fKn78iPj4+5cqRs6/3VVddVeHc5xqv6H93gDtQZIAqctVVVyklJUU33XSTXn/9dT311FP239q9vLwUFxd3wTlCQ0OVmJioxMREHT9+XN26ddOkSZPsRebqq6+u8BD/2d/sz+e/f8u+WO3atdO7776r7Ozs8877/fff6+eff9a7776r+++/3z7+56uwLpStSZMm+uKLL3TjjTc6nDa53OrUqaN//OMf+sc//qG8vDy1bdtWzz33nL3InCt/w4YN9d1336msrMyheOzYscO+/ex/V69erRMnTjgcldm9e3elMzrzegMmY40MUIV69OihDh06KDU1VadOnVJYWJh69Oiht956y/4P/5/99ttv9j8fOXLEYVtAQICaNm2q4uJi+1iTJk20Y8cOh8dt27ZN69atu2C2s58zUpkPxDtx4oTWr19f4bbPPvtM0h9rJ84379nf7P/8m7xlWXrllVcqne3OO+9UaWmpnn322XKPOXPmjFOfUnwxSktLy52SCQsLU926dR3eF39//wpPld1yyy3KycnR/Pnz7WNnzpzRa6+9poCAAPsRrfj4eJWUlOjtt9+271dWVma/HLoynHm9AZNxRAaoYuPGjdPf/vY3zZkzR48++qjS0tLUpUsXXX/99XrooYfUuHFj5ebmav369Tpw4IC2bdsmSWrRooV69OihmJgYhYaGavPmzfbLfs964IEH9PLLLys+Pl7Dhg1TXl6eZs6cqeuuu06FhYXnzRUTEyNJmjBhgu6++255eXmpX79+FX6Q2okTJ9S5c2d16tRJN998syIjI5Wfn6/Fixfrq6++0oABA9SmTRtJf5SrkJAQzZw5U4GBgfL391fHjh0VHR2tJk2aaOzYsTp48KCCgoL00UcfVbjW4my2UaNGKT4+XldddZXuvvtude/eXY888ohSUlKUlZWlPn36yMvLS7t27dKCBQv0yiuvaPDgwRf3RlXCsWPHVL9+fQ0ePFitW7dWQECAvvjiC23atEnTp093yD9//nwlJyerffv2CggIUL9+/fTwww/rrbfe0tChQ5WZmamoqCgtXLhQ69atU2pqqgIDAyX9cVqyQ4cOevzxx7V7925FR0dr6dKl9svGK3M0zZnXGzCa266XAq4gZy+/3rRpU7ltpaWlVpMmTawmTZpYZ86csSzLsvbs2WPdf//9VkREhOXl5WXVq1fPuu2226yFCxfaH/evf/3L6tChgxUSEmL5+flZ0dHR1nPPPWedPn3aYf7333/faty4seXt7W3dcMMN1ooVKyp1+bVlWdazzz5r1atXz/Lw8DjvpdglJSXW22+/bQ0YMMBq2LCh5ePjY9WoUcNq06aN9eKLL1rFxcUO+y9ZssRq0aKF5enp6XC58I8//mjFxcVZAQEBVq1atayHHnrI2rZtW7lL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AFwuTl+1dPToUYdbXl6eli9frvbt22vlypVVkREAAKBCTh+RCQ4OLjfWu3dveXt7Kzk5WZmZmS4JBgAAcCFOH5E5l/DwcO3cudNV0wEAAFyQ00dkvvvuO4f7lmUpOztbU6dO1Q033OCqXAAAABfkdJG54YYbZLPZZFmWw3inTp30zjvvuCwYAADAhThdZPbu3etw38PDQ7Vr15avr6/LQgEAAFSG00WmYcOGVZEDAADAaRe12DcjI0P9+vVT06ZN1bRpU91+++366quvXJ0NAADgvJwuMu+//77i4uJUo0YNjRo1SqNGjZKfn5969eql9PR0p+Z688031apVKwUFBSkoKEixsbH67LPP7NtPnTqlpKQk1axZUwEBARo0aJByc3OdjQwAAK5QTheZ5557TtOmTdP8+fPtRWb+/PmaOnWqnn32Wafmql+/vqZOnarMzExt3rxZPXv2VP/+/bV9+3ZJ0pgxY7Rs2TItWLBAGRkZOnTokAYOHOhsZAAAcIVyusj85z//Ub9+/cqN33777eUWAl9Iv379dMstt6hZs2a65ppr9NxzzykgIEAbNmxQQUGBZs2apZdfflk9e/ZUTEyMZs+erW+++UYbNmxwNjYAALgCOV1kIiMjtWrVqnLjX3zxhSIjIy86SGlpqebNm6eioiLFxsYqMzNTJSUliouLs+8THR2tBg0aaP369eecp7i4WIWFhQ43AABwZXL6qqXHH39co0aNUlZWljp37ixJWrdunebMmaNXXnnF6QDff/+9YmNjderUKQUEBGjRokVq0aKFsrKy5O3trZCQEIf9w8PDlZOTc875UlJSNHnyZKdzAAAA8zhdZIYPH66IiAhNnz5dH374oSSpefPmmj9/vvr37+90gGuvvVZZWVkqKCjQwoULlZCQoIyMDKfnOWv8+PFKTk623y8sLLykI0UAAKD6crrISNIdd9yhO+64wyUBvL291bRpU0lSTEyMNm3apFdeeUV33XWXTp8+rfz8fIejMrm5uYqIiDjnfD4+PvLx8XFJNgAAUL05vUZm06ZN2rhxY7nxjRs3avPmzZccqKysTMXFxYqJiZGXl5fDepydO3dq3759io2NveTnAQAA5nO6yCQlJWn//v3lxg8ePKikpCSn5ho/frzWrl2rX375Rd9//73Gjx+vNWvW6N5771VwcLCGDRum5ORkrV69WpmZ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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "result = service.run(circuit, name=\"Cirq example\", repetitions=100)\n", - "_ = cirq.plot_state_histogram(result, plt.subplot())\n", - "plt.show()" - ] + "outputs": [], + "source": "# Now we'll send the job to our backend for processing and plot the results.\n\nresult = service.run(circuit, name=\"Cirq example\", repetitions=100)\n_ = cirq.plot_state_histogram(result, plt.subplot())\nplt.show()" + }, + { + "cell_type": "markdown", + "source": "## And that's a wrap!\n\nTo continue learning with Cirq, check out more examples and documentation at https://quantumai.google/cirq", + "metadata": {} } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "venv (3.14.2)", "language": "python", "name": "python3" }, @@ -122,9 +100,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.14.2" } }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/cuda-quantum/Dockerfile b/cuda-quantum/Dockerfile index 7de781a..9b9a7bf 100644 --- a/cuda-quantum/Dockerfile +++ b/cuda-quantum/Dockerfile @@ -1,14 +1,14 @@ -# We start from a minimal Python 3.11 image +# Start from a minimal Python 3.11 image FROM --platform=linux/x86_64 python:3.11 -# Install Jupyter and CUDA Quantum -RUN pip install jupyter cuda-quantum +# Install Jupyter and CUDA-Q +RUN pip install --no-cache-dir jupyter cudaq -# Copy the main.ipynb file into the container -COPY main.ipynb /workspace/ +# Copy the main CUDA-Q notebook and helper script into the container +COPY main.ipynb helpers.py /workspace/ # Set the working directory WORKDIR /workspace -# The command to run when the container starts -CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--NotebookApp.token=''", "--allow-root"] +# Run Jupyter Notebook, listening on all interfaces with no auth token. +CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--NotebookApp.token=", "--allow-root"] diff --git a/cuda-quantum/README.md b/cuda-quantum/README.md index 8279191..8cfe36b 100644 --- a/cuda-quantum/README.md +++ b/cuda-quantum/README.md @@ -4,7 +4,7 @@ --- -If `pip install cuda-quantum` fails, build and run the Dockerfile: +If `pip install cudaq` fails, build and run the Dockerfile: ```shell docker build -t cuda-quantum -f Dockerfile . && docker run -p 8888:8888 -it cuda-quantum diff --git a/cuda-quantum/helpers.py b/cuda-quantum/helpers.py new file mode 120000 index 0000000..cf37903 --- /dev/null +++ b/cuda-quantum/helpers.py @@ -0,0 +1 @@ +../helpers.py \ No newline at end of file diff --git a/cuda-quantum/main.ipynb b/cuda-quantum/main.ipynb index a33c9d2..2d04a45 100644 --- a/cuda-quantum/main.ipynb +++ b/cuda-quantum/main.ipynb @@ -2,69 +2,64 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%capture\n", "\n", - "!pip install cuda-quantum" + "# First, we install the essential libraries to our current Python runtime.\n", + "# \"%%capture\" (above) captures and in this case, hides the output of this \n", + "# cell, so you can comment it out if you need help debugging this step.\n", + "\n", + "%pip install cudaq" ] }, + { + "cell_type": "markdown", + "source": "# CUDA-Q\n\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ionq-samples/getting-started/blob/main/cuda-quantum/main.ipynb)\n\n[CUDA-Q](https://nvidia.github.io/cuda-quantum/latest/) is NVIDIA's platform for hybrid quantum-classical computing. It provides a unified programming model for quantum algorithm development and seamlessly integrates with classical computing workflows.", + "metadata": {} + }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "import cudaq\n", - "\n", - "import os\n", - "from getpass import getpass\n", - "\n", - "api_key = os.getenv('IONQ_API_KEY') or getpass('Enter your IonQ API key: ')\n", - "os.environ['IONQ_API_KEY'] = api_key # Remove when set_target takes api_key\n", - "cudaq.set_target('ionq', qpu='simulator')" - ] + "source": "import os\n\nimport cudaq\n\nfrom helpers import get_ionq_api_key\n\napi_key = get_ionq_api_key()\nos.environ[\"IONQ_API_KEY\"] = api_key # Remove when set_target takes api_key\ncudaq.set_target(\"ionq\", qpu=\"simulator\")" }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{ 3:50 0:50 }\n", - "\n" - ] - } - ], - "source": [ - "# Define the kernel and allocate two qubits\n", - "kernel = cudaq.make_kernel()\n", - "qubits = kernel.qalloc(2)\n", - "\n", - "# Apply a Hadamard gate to the first qubit\n", - "kernel.h(qubits[0])\n", - "\n", - "# Apply a CX gate from the first to second qubit\n", - "kernel.cx(qubits[0], qubits[1])\n", - "\n", - "# Execute the kernel on the computer and print the result\n", - "print(cudaq.sample(kernel))" - ] + "outputs": [], + "source": "# Now we set up our circuit. In this case, we're creating a Bell state with two\n# qubits, applying an H gate to qubit-0, a controlled-X gate to both qubits.\n\nSHOTS = 100\n\n\n@cudaq.kernel\ndef bell_state():\n qubits = cudaq.qvector(2)\n h(qubits[0])\n x.ctrl(qubits[0], qubits[1])\n\n\n# Execute the kernel on IonQ's simulator and display the results.\n\nresult = cudaq.sample(bell_state, shots_count=SHOTS)\nprint(result)" + }, + { + "cell_type": "markdown", + "source": "## And that's a wrap!\n\nTo explore more about CUDA-Q and quantum computing with NVIDIA, check out the official documentation at https://nvidia.github.io/cuda-quantum/", + "metadata": {} } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "venv (3.14.2)", "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.14.2" + }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/environment.yml b/environment.yml index cba491a..c23d3cc 100644 --- a/environment.yml +++ b/environment.yml @@ -5,12 +5,13 @@ channels: dependencies: - python=3.11 - pip - - matplotlib - jupyter + - pytest + - nbconvert # Add other dependencies here, for Conda packages. - pip: # Pip-only packages here, if any. - - qiskit + - qiskit[visualization] - qiskit-ionq - cirq - cirq-ionq @@ -20,3 +21,4 @@ dependencies: - cudaq - pylatexenc - requests + - ipykernel diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..0a246e7 --- /dev/null +++ b/helpers.py @@ -0,0 +1,17 @@ +import os +from getpass import getpass + + +def get_ionq_api_key(env_var: str = "IONQ_API_KEY") -> str: + """Return the IonQ API key, or raise a clear error if it can't be retrieved.""" + api_key = os.getenv(env_var) + if api_key: + return api_key + + try: + return getpass(f"Enter your IonQ API key ({env_var}): ") + except (EOFError, KeyboardInterrupt) as exc: + raise RuntimeError( + f"No {env_var} environment variable is set and an interactive prompt " + "isn't available. Please set your IonQ API key before running this notebook." + ) from exc diff --git a/pennylane.ipynb b/pennylane.ipynb index 3c7a752..54d07dc 100644 --- a/pennylane.ipynb +++ b/pennylane.ipynb @@ -28,88 +28,41 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "import pennylane as qml\n", - "\n", - "import os\n", - "from getpass import getpass\n", - "\n", - "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", - "\n", - "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", - "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", - " \n", - "api_key = os.getenv('IONQ_API_KEY') or getpass('Enter your IonQ API key: ')\n", - "\n", - "# We need to specify the device where the circuit will be executed. In\n", - "# this case we're using the `ionq.simulator`, but if you have QPU access you\n", - "# can specify it here to run the job on a QPU directly.\n", - "\n", - "dev = qml.device(\n", - " 'ionq.simulator',\n", - " api_key=api_key,\n", - " wires=2,\n", - ")" - ] + "source": "from functools import partial\n\nimport matplotlib.pyplot as plt\nimport pennylane as qml\n\nfrom helpers import get_ionq_api_key\n\n# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n\n# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n# should find it. Otherwise you'll be prompted to enter your API key manually.\n\napi_key = get_ionq_api_key()\n\n# We need to specify the device where the circuit will be executed. In\n# this case we're using the `ionq.simulator`, but if you have QPU access you\n# can specify it here to run the job on a QPU directly.\n\ndev = qml.device(\n 'ionq.simulator',\n api_key=api_key,\n wires=2,\n)" }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "@qml.qnode(dev)\n", - "def circuit():\n", - " qml.Hadamard(wires=0)\n", - " qml.CNOT(wires=[0, 1])\n", - " return qml.counts()" - ] + "source": "# Now we set up our circuit. In this case, we're creating a circuit with two\n# qubits, applying an H gate to qubit-0, a CNOT gate to both qubits.\n\n@partial(qml.set_shots, shots=100)\n@qml.qnode(dev)\ndef circuit():\n qml.Hadamard(wires=0)\n qml.CNOT(wires=[0, 1])\n return qml.counts()" }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgcAAAFACAYAAAAoFN9yAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABNWElEQVR4nO3dd3xTVeMG8Cdpm500nXQAIkjZQ9mi4qsiIL4CirJElorgQFRwIOqLoqIo+APELcoQFWWoIIIKoggICshWBBHooCN7tsnvj9LITVpI0owmfb6fTz96T9J7T0POzZNzzz1H5Ha73QgNEYBQ7Yv8Jzr7X772kcPXPHJE5/w/X+/Q4Xs48mLqM1IUwnBAREREcUAc7QoQERFR3cJwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJMBwQERERAIMB0RERCTAcEBEREQCDAdEREQkwHBAREREAgwHREREJJAY7QoQRZLZbMaBAwdw6tQplJaWQqfToaysDFdccQX69OkT7eoRRRXbB1VJBCAC4I52RYjCYf/+/fj666+xc+dO7N69G4cPH4bbXf3bfe7cuVCpVNBqtVCpVFAoFFCr1UhJSUFycjLUajUSEhIi/BcQhQ/bB9VEdPaNwHBAcaOoqAiLFy/Ghx9+iL1794ZsvyKRCCkpKdBoNFAqlZDL5ZBIJJBIJFCpVJDL5ZDJZJBIJEhISIBYXHnV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TvRXlnS73TCbrTBbLDCaLNDpDSgqLkVJqQ56gwl2uwM2ux1Wmx0mkwU6gxF/HT+Jw38eQ9GZC0+S1bJlS6xbtw5NmjQJ/x8TRxgOiIjikNPpxIgRI/Dpp5/W+JweXTpgYP9r0a1TOzS9qCFysjP9WojI7XbD6SyH1WaDxWKD0WSG2WKF2WJFaZke+YVnoDeYYDZbYLHaYLZYodMbYTSZUaYzwGA0wWK1wWqzQ6c3whLCFTSrpKenY8aMGbjzzjuRlBR760BEG8MBEVGcKi8vx+zZs/Hss8/CYrnwdNJJSYnIycpEWqoWSYmJEIlEcJY74XA4K7+5my0wmsywWu1wuVwR+AsCl52djaFDh2L69OlISUmJdnViFsMBEVGcO3HiBB555JHz9iLEKpFIhKZNm2LgwIEYPHgwunbtCrGYk//WFsMBEVE98dNPP+HNN9/E6tWrYTAYol2daiUmJiIjIwMZGRnQarWQy+WQSqWQyWRQq9VQqVTIzc1FXl4eWrRogaZNm3rW06DQYTggIqpn7HY7vvvuO6xevRpbtmzBsWPHYLXW7rp/YmIilEol1Go1srOzkZaWBqVSCaVSCYVCgeTkZGg0Gmi1Ws+Hvlwuh0ajQYMGDaBWq6FWqyGTyeJmUqpYxnBARFTPud1uFBUV4e+//8bJkydhNBrhdDrhdrshkUggkUgglUqhUqmg0Wggl8shk8mgUCggl8uhVqshlUqj/WdQCDEcEBERkQBHbRAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkYAYAG8oJSIiIg/2HBAREZGAGADnOSAiIiIP9hwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAwwEREREJMBwQERGRAMMBERERCTAcEBERkQDDAREREQkwHBAREZEAw8G/ROf8UPTx3yL0+JqGHl/PyOB7N/TO+5r+PwaMtPff8wnlAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = qml.draw_mpl(circuit, style='sketch')()" - ] + "outputs": [], + "source": "# Before submitting the job, we can visualize the circuit using draw_mpl().\n\nfig, ax = qml.draw_mpl(circuit, style='sketch')()" }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'00': 516, '11': 508}\n" - ] - } - ], - "source": [ - "results = circuit()\n", - "print({k: v.item() for k, v in results.items()})" - ] + "outputs": [], + "source": "# Now we'll send the job to our backend for processing and plot the results.\n\ncounts = circuit()\n\n# Robust scalar conversion (works whether values are Python ints, numpy scalars, torch scalars, etc.)\ncounts = {k: int(v) for k, v in counts.items()}\n\n# Optional: If you want missing outcomes shown as 0, define the QNode with counts(all_outcomes=True).\n\nlabels = sorted(counts.keys())\nvalues = [counts[k] for k in labels]\n\nplt.bar(labels, values)\nplt.xlabel(\"bitstring\")\nplt.ylabel(\"counts\")\nplt.title(\"Measurement counts\")\nplt.show()" + }, + { + "cell_type": "markdown", + "source": "## And that's a wrap!\n\nTo continue learning with PennyLane, check out more examples and tutorials at https://pennylane.ai/qml/", + "metadata": {} } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "venv (3.14.2)", "language": "python", "name": "python3" }, @@ -123,9 +76,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.14.2" } }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b2747aa --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "ionq-getting-started" +version = "1.0.0" +description = "IonQ Quantum Computing Samples - Getting started with various quantum SDKs" +readme = "README.md" +requires-python = ">=3.8,<3.12" +license = { text = "Apache-2.0" } + +dependencies = [ + # Core dependencies + "jupyter>=1.0.0", + "pytest>=7.0.0", + "nbconvert>=7.0.0", + "requests>=2.28.0", + "ipykernel>=6.0.0", + + # Quantum SDKs + "qiskit[visualization]>=1.0.0", + "qiskit-ionq>=0.5.0", + "cirq>=1.0.0", + "cirq-ionq>=1.0.0", + "pennylane>=0.30.0", + "pennylane-ionq>=0.30.0", + "projectq>=0.8.0", + "cudaq>=0.6.0", + + # Visualization and utilities + "matplotlib>=3.5.0", + "pylatexenc>=2.10", + "pyqasm>=0.1.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.0.0", + "nbconvert>=7.0.0", +] + +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py"] diff --git a/qbraid.ipynb b/qbraid.ipynb index b2dc80c..b1547b7 100644 --- a/qbraid.ipynb +++ b/qbraid.ipynb @@ -13,60 +13,40 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "%%capture\n", - "\n", - "# First, we install the essential libraries to our current Python runtime.\n", - "# \"%%capture\" (above) captures and in this case, hides the output of this\n", - "# cell, so you can comment it out if you need help debugging this step.\n", - "\n", - "%pip install qbraid matplotlib" - ] + "source": "%%capture\n\n# First, we install the essential libraries to our current Python runtime.\n# \"%%capture\" (above) captures and in this case, hides the output of this\n# cell, so you can comment it out if you need help debugging this step.\n\n%pip install qbraid matplotlib pyqasm" }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "import os\n", - "from getpass import getpass\n", "from qbraid.runtime.ionq import IonQProvider\n", + "from helpers import get_ionq_api_key\n", "\n", "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", "\n", "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", "\n", - "api_key = os.getenv(\"IONQ_API_KEY\") or getpass(\"Enter your IonQ API key: \")\n", + "api_key = get_ionq_api_key()\n", "\n", "provider = IonQProvider(api_key=api_key)" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "# Now we set up our circuit. In this case, we're creating a circuit with two\n", - "# qubits, applying an H gate to qubit-0, a CXGate to both,.\n", - "\n", - "program = \"\"\"\n", - "OPENQASM 3;\n", - "include \"stdgates.inc\";\n", - "qubit[2] q;\n", - "h q[0];\n", - "cx q[0], q[1];\n", - "\"\"\"" - ] + "source": "# Now we set up our circuit using OpenQASM 3. In this case, we're creating a\n# circuit with two qubits, applying an H gate to qubit-0, a CX gate to both.\n\nprogram = \"\"\"\nOPENQASM 3;\ninclude \"stdgates.inc\";\nqubit[2] q;\nh q[0];\ncx q[0], q[1];\n\"\"\"" }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -89,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -112,30 +92,20 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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Zz9TS0tLtzUHAABwNl0KMnfffbeKiookSaWlpZo5c6YuueQSrVmzRvfee2+3NggAAHAmXQoyRUVFysrKkiStWbNGV199tVauXKkVK1Zo7dq13dkfAADAGXUpyHi9Xnk8HknShg0bdMMNN0iSEhISVFdX133dAQAAnEWXgszo0aP161//Wi+88II2bdqkKVOmSJIOHDggh8PRrQ0CAACcSZeCzOOPP67t27frnnvu0c9//nMNHjxYkvTyyy/rqquu6tYGAQAAziSoK3caMWJEp08tfeHf//3fFRTUpU0CAACcty6dkUlNTdXRo0dPqTc3N2vIkCFfuSkAAIBz0aUgc/DgQbnd7lPqLpdLhw8f/spNAQAAnIvzeh/ojTfe8P373XffVWRkpO+22+1WXl6eUlJSuq87AACAszivIHPLLbdIkgzD0OzZszstCw4OVnJysn7/+993W3MAAABnc15B5ovvjklJSVF+fr5iYmIuSFMAAADnoksfMTpw4EB39wEAAHDeuvxZ6by8POXl5ammpsZ3puYLzz333FduDAAA4Mt0KcgsXrxYDz/8sEaPHq24uDgZhtHdfQEAAHypLgWZZ555RitWrNDtt9/e3f0AAACcsy59j0xLSws/RQAAAAKuS0Hm+9//vlauXNndvQAAAJyXLr211NzcrD/84Q/asGGDhg8fruDg4E7LH3vssXPaztNPP62nn35aBw8elCRdeumlevDBB3X99df7xvnxj3+sVatWyeVyKTc3V0899RS/sA0AACR1Mcjs2rVLWVlZkqQ9e/Z0WnY+F/4OHDhQjzzyiNLS0uT1evU///M/uvnmm/XZZ5/p0ksv1cKFC7Vu3TqtWbNGkZGRuueeezR16lR98sknXWkbAABcZLoUZP73f/+3Wwa/8cYbO93+zW9+o6efflpbtmzRwIED9eyzz2rlypWaOHGiJGn58uUaOnSotmzZojFjxnRLDwAAwLq6dI3MheB2u7Vq1So1NTUpJydHBQUFam1t1eTJk33rZGRkKDExUZs3bz7jdlwul5xOZ6c/AABwcerSGZkJEyac9S2kDz744Jy3tXv3buXk5Ki5uVkRERF69dVXNWzYMO3YsUMhISHq06dPp/UdDoeqqqrOuL0lS5Zo8eLFp9S3bdumiIgISVJWVpYaGhpUUlLiW56RkSGbzaa9e/f6asnJyYqOjlZB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+bXXXquCgoKv3BQAAMC5OK8gU11dfdqPXX8hKChItbW1X7kpAACAc3FeQWbAgAHas2fPGZfv2rVLcXFxX7kpAACAc3FeQeaGG27QAw88oObm5lOWnTx5Ug899JC+9a1vdVtzAAAAZ3NeH7/+xS9+oVdeeUVDhgzRPffco/T0dEnS3//+dy1btkxut1s///nPL0ijAAAA/9d5BRmHw6G//vWv+td//Vfdf//98nq9kiTDMJSbm6tly5bJ4XBckEYBAAD+r/P+QrykpCS9/fbbOn78uIqLi+X1epWWlqaoqKgL0R8AAMAZdembfSUpKipK2dnZ3dkLAADAeenSby0BAAD0BAQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQENMkuWLFF2drZ69+6t/v3765ZbblFhYWGndZqbmzVv3jxFR0crIiJC06ZNU3V1dYA6BgAAPUlAg8ymTZs0b948bdmyRe+//75aW1t17bXXqqmpybfOwoUL9eabb2rNmjXatGmTKioqNHXq1AB2DQAAeoqgQA6+fv36TrdXrFih/v37q6CgQFdffbXq6+v17LPPauXKlZo4caIkafny5Ro6dKi2bNmiMWPGBKJtAADQQ/Soa2Tq6+slSX379pUkFRQUqLW1VZMnT/atk5GRocTERG3evDkgPQIAgJ4joGdkOvJ4PFqwYIHGjh2ryy67TJJUVVWlkJAQ9enTp9O6DodDVVVVp92Oy+WSy+Xy3XY6nResZwAAEFg9JsjMmzdPe/bs0ccff/yVtrNkyRItXrz4lPq2bdsUEREhScrKylJDQ4NKSkp8yzMyMmSz2bR3715fLTk5WdHR0SooKPDVHA6HkpKStGPHDn1viFuSdLjJ0HtHTF030K34S9rWa2iV1hywKae/R0P7eH33X15kamgfr8b099deOWiqV5CUO9Djq+VVmDraLE1P9dcK6gztPGZqTppbptFW2+809FGVqW8nuRUV2laraZbeKrNp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evXVV3XLLbdIkv76179q7NixqqioUFxcnG+96dOnyzAMrV69+rTbcblcvoOVJDmdTiUkJKi+vl52u71be06+b123bg+42Bx8ZEqgW+gW7OvAmV2o/dzpdCoyMvJLn7977FtLsbGxktTpldEXt79YdjqhoaGy2+2d/gAAwMWpxwaZlJQUxcbGKi8vz1dzOp369NNPlZOTE8DOAABATxHQa2QaGxs7ved94MAB7dixQ3379lViYqIWLFigX//610pLS1NKSooeeOABxcfH+95+AgAA/9wCGmS2bdumCRMm+G4vWrRIkjR79mytWLFC9957r5qamvSDH/xAJ06c0Lhx47R+/XqFhYUFqmUAANCDBDTIjB8/Xme71tgwDD388MN6+OGHv8auAACAVfTYa2QAAAC+DEEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYliWCzLJly5ScnKywsDBdeeWV2rp1a6BbAgAAPUCPDzKrV6/WokWL9NBDD2n79u0aMWKEcnNzVVNTE+jWAABAgPX4IPPYY4/prrvu0ty5czVs2DA988wzuuSSS/Tcc88FujUAABBgQYFu4GxaWlpUUFCg+++/31czTVOTJ0/W5s2bT3sfl8sll8vlu11fXy9Jcjqd3d6fx/WPbt8mcDG5EPtdILCvA2d2ofbzL7br9XrPul6PDjJ1dXVyu91yOByd6g6HQ3//+99Pe58lS5Zo8eLFp9QTEhIuSI8AzixyaaA7AHChXej9vKGhQZGRkWdc3qODTFfcf//9WrRoke+2x+PRsWPHFB0dLcMwAtgZLjSn06mEhASVl5fLbrcHuh0AFwD7+T8P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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from qbraid.visualization import plot_histogram\n", - "\n", - "plot_histogram(counts)" - ] + "outputs": [], + "source": "# And once the job has run, we can plot the results.\n\nfrom qbraid.visualization import plot_histogram\n\nplot_histogram(counts)" + }, + { + "cell_type": "markdown", + "source": "## And that's a wrap!\n\nTo continue learning with qBraid, check out more examples and documentation at https://docs.qbraid.com/", + "metadata": {} } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "venv (3.14.2)", "language": "python", "name": "python3" }, @@ -149,9 +119,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.14.2" } }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/qiskit.ipynb b/qiskit.ipynb index d2b12dd..abb6835 100644 --- a/qiskit.ipynb +++ b/qiskit.ipynb @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "151d6c64", "metadata": {}, "outputs": [], @@ -30,21 +30,21 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "f3042105", "metadata": {}, "outputs": [], "source": [ - "import os, qiskit_ionq\n", - "from getpass import getpass\n", + "import qiskit_ionq\n", + "from helpers import get_ionq_api_key\n", "\n", "# Before you begin, get your API key from https://cloud.ionq.com/settings/keys\n", "\n", "# If your API key is stored as \"IONQ_API_KEY\" in your local environment, this\n", "# should find it. Otherwise you'll be prompted to enter your API key manually.\n", "\n", - "api_key = os.getenv('IONQ_API_KEY') or getpass('Enter your IonQ API key: ')\n", - "provider = qiskit_ionq.IonQProvider(api_key)\n", + "api_key = get_ionq_api_key()\n", + "provider = qiskit_ionq.IonQProvider(token=api_key)\n", "\n", "# We need to specify a backend, which is where the circuit will be executed. In\n", "# this case we're using the `ionq_simulator`, but if you have QPU access you\n", @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "id": "bd2c2829", "metadata": {}, "outputs": [], @@ -73,18 +73,18 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "id": "09166bbb", "metadata": {}, "outputs": [ { "data": { - "image/png": "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Lff8X/7yF2bNmkVhYWGVtV66dKnsZ09PT6ZMmcKCBQsYPHgw3bp1Y+DAgfTt25d+/foREOD48HBHD1dAyUjdhW+tBWBc3MDbanCEiEhN1LtDu1W9HEeWR0VF1XiqqZtnANq7dy99+/bF09OTl156ibi4OCIiIvD19cVisbB69WomTJhQYdag4uJili9fzrJlyzh+/HjZ897e3jz22GMsXryYwMDAGtVzMyPnSNUbFZHbgZFzpPWuR+pMpQOBNm/ezMiRI2vc7v333wdg2rRp/OlPf6qw/Oae6M08PDyYPHkykydPJiUlhd27d7Njxw7Wr1/P22+/TXJyMjt27LD7dWTnXDN8jrS4uFjnWUVEKqEgvYXY2Fji4+P54Ycf7ArSpKQkAPr2rfzOB99+W/2sQOHh4Tz66KM8+uijTJs2jU6dOvH555+TlJREmzZtalwLOH7sX71REbld6Bypizz88MOsWbOGlStX8vzzz5f1UKvTqFHJP8jP7xUIJQOQtmzZYlcdsbGxNG7cmKysLM6dO2d3kDpyuELnRkVEaqbezGzkCnFxcfTr14/Tp08zePBgfvjhh3LLi4uL+eabb3j22WfLjfi95557AHjllVfKzah09OhRRo4cWekdDo4dO8YzzzzDt99+W+48bVFREa+++ipZWVlYrVZiYyufr9LZNIuRiEjNaLBRNcszMjKIi4srm3ChdevWhISEcO3aNU6ePElubsl5w4SEBDp0KLkNUnZ2Nt26dSMxMREvLy/at29PcXExCQkJhIaG8txzzzF79uxyg43i4+O56667APD39ycyMhJPT09Onz5ddk51+fLl/Pa3v3Xo92OP0t5o/o0CHn9gsHqjIiK3oB5pNYKDg/nqq6945513GDRoELm5uRw8eJCkpCTatWvHlClT+Oqrr4iOji5r4+/vz549e3j66adp2rQpP/74Izk5OUyaNInDhw8TFhZWYT/R0dGsWrWKRx55hNDQUE6dOsWRI0ewWq2MHj2a3bt3uyVEAa7n36DVHc3VGxURqYF60yMV57uefwOrd0OzyxARqdUUpCIiIgbo0K6IiIgBClIREREDFKQiIiIGKEhFREQMUJCKiIgYoCAVERExQEEqIiJigIJURETEAAWpiIiIAQpSERERAxSkIiIiBihIRUREDFCQioiIGKAgFRERMUBBKiIiYoCCVERExAAFqYiIiAEKUhEREQMUpCIiIgYoSEVERAxQkIqIiBigIBURETFAQSoiImKAglRERMQABamIiIgBClIREREDFKQiIiIGKEhFREQMUJCKiIgYoCAVERExQEEqIiJigIJURETEAAWpiIiIAQpSERERAxSkIiIiBihIRUREDFCQioiIGKAgFRERMUBBKiIiYsD/Byk6/HqoTJpWAAAAAElFTkSuQmCC", + "image/png": "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", "text/plain": [ "
" ] }, - "execution_count": 8, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -99,18 +99,18 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "id": "6aa9658d", "metadata": {}, "outputs": [ { "data": { - "image/png": "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PWWqw2K/1von12C1WmWxWJz+Avvt/Xl2u10Wi6XY9fPKymazKTU1VV999ZWef/553XTTTVq7dq18fX31wQcf6IEHHtALL7ygv/71r0Xe+8ILL2ju3Ln6n//5H40YMUKpqam68cYb1adPH23btq1I/6+//lpRUVGaMmWKFi1aVGw9xc3ktWjRQunp6Y6QWB1/0U78OzN5qD2WTGImjzHVrjH9aREzeag9lk6p3uMpIyNDgYGByszMLHGCTarETF5sbGxF31ouVqtVzZs314QJExQUFKRRo0Zpzpw5mj9/vmNGrqSZt8JLqYX9ytu/OJ6envL09CzS7uHhUWT9Pjc3t2IvC5e01ExJ7b/dL+BqJf1OFtdutVodSx6Vpb2k46a6jyfGVLfHBNQmrjqeivQrU69iuOJrzaKioiRdfXhCKv0eut/es+ft7a2mTZvq6NGjKigoKPKDK+0ePwAAgLqiwk/XukJqaqqk//eXXLt27dSsWTNt375dubm5Tn1zc3O1fft2tW7dWi1atHC0R0REOLb9VuH6eP369auuIQAAANSICoe8EydOlPlfefz444+6cOFCkfYLFy7oySeflHT1Rlvp6rXscePGKScnR6+88opT/1deeUU5OTkaP368U/uf/vQnSVfX0bty5Yqjfd26dUpISFBUVJRCQkLKVTMAAEBtU+HLta1atSrTQsgWi6XMj/pK0urVq/X666+rb9++atWqlXx9fXXy5EmtW7dOZ8+e1e23364nnnjC0f/ZZ5/VF198ofnz5+v7779Xt27d9N133ykuLk49evTQ1KlTnfYfGRmpcePGafny5erWrZuGDRumU6dO6aOPPlKjRo309ttvl7lWAACA2qrCIW/MmDHFhrzMzEzt3btXR48eVUREhFq1alWu/d55551KTU3Vjh07tHPnTuXk5MjPz0+dO3fWH//4Rz3yyCNONxx6e3try5YtmjVrlj799FPFx8eradOmeuqppzRz5kx5eXkV+YylS5eqU6dOWrZsmRYtWqSGDRtqxIgRmjNnjtq2bVvunwUAAEBtU+ElVK7Fbrdr4cKF+tvf/qZdu3apTZs2Vf0RtUZWVpb8/PxKfYy5ssa/WW27BsrtnamurgBwxjkStUl1nyPLmj2q5cGLwoWLb7rpJj3zzDPV8REAAAC4hmp9uvaWW27R5s2bq/MjAAAAUIxqDXk///xzuR66AAAAQNWo8IMXJbHZbDp58qRWrFihL774QgMHDqzqjwAAAEApKhzyCr+7tiR2u10BAQFauHBhRT8CAAAAFVThkNevX79iQ57ValVAQIB69Oihhx9+WI0bN65UgQAAACi/Coe8wu+PBQAAQO1Tp767FgAAAGVTJQ9ebN++XYmJicrKypKvr6+6du2qPn36VMWuAQAAUAGVCnk7duzQww8/rMOHD0u6+rBF4X167dq1U2xsrHr37l35KgEAAFAuFQ55P/zwg6KionThwgUNHjxYkZGRatq0qdLS0hQfH6+4uDhFR0dr165d6tixY1XWDAAAgFJUOOS9/PLLunLlitauXas77rjDadu0adO0fv16DR8+XC+//LJWrVpV6UIBAABQdhV+8CIhIUEjR44sEvAK3XHHHRo5cqTi4+MrXBwAAAAqpsIhLzMzU61bt75mn9atWyszM7OiHwEAAIAKqnDIa9asmXbt2nXNPv/5z3/UrFmzin4EAAAAKqjCIW/48OFKSEjQjBkzdOnSJadtly5d0syZMxUfH6+777670kUCAACgfCr84MWMGTO0Zs0azZ07V0uXLtWtt96qG264QadPn9a3336rM2fOqE2bNpoxY0ZV1gsAAIAyqHDICwwM1K5du/Tss89q1apVWrt2rWNb/fr19fDDD2v+/Plq1KhRlRQKAACAsqvUYshBQUF69913tXTpUv3000+Ob7wICwuTh4dHVdUIAACAcip3yJszZ45yc3M1e/ZsR5Dz8PBQp06dHH2uXLmiF154QT4+PnruueeqrloAAACUSbkevNi4caNeeuklBQYGXnOmrl69egoMDNQLL7zAOnkAAAAuUK6Q99577ykgIECTJ08ute+kSZPUqFEjxcbGVrg4AAAAVEy5Qt6OHTs0aNAgeXp6ltrX09NTgwYN0vbt2ytcHAAAACqmXCEvNTVVbdq0KXP/1q1b69SpU+UuCgAAAJVTrpBntVqVl5dX5v55eXmyWiu83jIAAAAqqFwJrFmzZjpw4ECZ+x84cEA33nhjuYsCAABA5ZQr5N1+++3avHmzjh07VmrfY8eOafPmzerXr19FawMAAEAFlSvkTZo0SXl5eRo5cqTS09NL7Hf27Fn94Q9/UH5+viZMmFDpIgEAAFA+5VoMuVu3bpo6darefPNNdezYUX/+858VGRmp5s2bS5JO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L+m4qcrjqSy1M6a6NaYrlywCaovz56v3eMrIyJAkp2OnONdlyKuMefPmafbs2UXaW7du7YJqANd4b7qrKwCA2qumzpHZ2dklTlhJ12nIK/yBlDRbl5WVpYCAgGK3TZ8+XU8++aTjtc1mU0ZGhgIDA2Wx8JdkbZaVlaUWLVooOTlZvr6+ri4HAGoVzpF1h91uV3Z2tpo1a3bNftdlyCu8Fy8pKUndu3d32paWlqacnBzdeuutxb7X09NTnp6eTm3+/v7VUieqh6+vLycwACgB58i64VozeIWuywcvIiIiJElxcXFFtm3YsMGpDwAAQF1ksZd2156B8vPzFRoaqpMnT2rXrl2OtfIyMzN166236tixYzp48KBatWrl0jpRtbKysuTn56fMzEz+SgWA3+AcaZ7r8nKtu7u7li9frujoaPXr18/pa82OHz+u1157jYBnIE9PT82cObPI5XYAAOdIE12XM3mFdu/erZkzZ2rHjh3Ky8tTp06d9OSTT2r06NGuLg0AAKBSruuQBwAAYKrr8sELAAAA0xHyAAAADETIAwAAMBAhDwAAwECEPAAAAAMR8mC0wofH7Xa7eJAcAHA9YQkVAAAAA12X33iB68Mvv/yi/fv3KykpSdnZ2erZs6dCQ0MVGBgod/erv/o2m01WKxPaAADzEPJgpHXr1mnOnDnasWOHU3tgYKAGDhyo0aNH684775SHh4eLKgQA1ysoKJCbm5ury0A14XItjJOcnKz+/fsrNzdXMTExioyM1JEjR/T9999r79692rdvny5fvqwOHTrohRde0L333itPT0/Z7XZZLBZXlw8A1e63VzEK71su7coG58m6hZk8GGfp0qU6d+6cli9frt///vdO21JSUrRjxw59+eWX+uCDD/Tggw8qJSVFzz77LCcuANeNpUuXKiEhQWPGjFFERIQaNmzoOAfabDZJKjbwcZ6sW5jJg3F69eolLy8vffzxxwoKClJ+fr4sFkuRSxLx8fF66qmn9OOPP2rJkiV65JFHXFQxANSs1q1b6/jx4/L09FSXLl0UFRWloUOHqmfPnk5BLj8/X+7u7rpw4YKWLVumLl26KDIy0oWVozwIeTBKTk6ORowYoZSUFO3Zs0cNGjRwuizx20sS33//vQYOHKjbb79dX3zxBZciABjvhx9+UKdOndS9e3cFBARo48aNkiRvb2/16dNHQ4cOVVRUlMLCwhzv2bZtm/r166fbbrtN27Ztc1XpKCceK4RRGjZsqO7du+vgwYNatWqVpKKXHApf22w2hYeHq1+/fvrpp590/PhxAh4A4+3fv1+SdP/99ysuLk4//fSTXn31Vf3ud79TXFycpk6dqgEDBuj+++/Xf//3f+vcuXPavXu3JGn69OmuLB3lxEwejHPy5EkNGTJEBw4c0OTJkxUTE6OOHTuqfv36jj6FlyCysrI0btw4/ec//9Hx48ddWDUA1Ixly5bpz3/+s/79739ryJAhTtu+/fZbffjhh/rkk0+UkpIiSWrXrp2ysrJ08eJFnT9/3gUVo6KYyYNxbrzxRr388stq1aqVFi9erMcee0yvvfaaEhISdPz4cV26dMmxTt5XX32lhISEIic6ADCR3W5X586dNXXqVLVv396pXZJ69Oih119/XYcOHdJXX32lMWPG6PTp0zp9+rQeeughV5WNCmImD8b47f10GRkZmjdvnlavXq3k5GQFBwfr5ptvVrNmzdSgQQNdvHhRq1evVuvWrfX5558rNDTUhdUDQM3JyclRvXr1VK9evSLbfnsunTx5spYsWaLvvvtOXbt2rcEqUVmEPBil8OSUkpKiZs2ayWq16sCBA1qzZo0SEhL0f//3f0pOTpYkBQQEqGvXrnrrrbd00003ubhyAKg9Cs+lP//8s0aPHq3MzEwlJSW5uiyUEyEPRsjPz9f27dv17rvv6tChQ7JYLGrQoIF69OihUaNGKTw8XHa7XcnJybp48aKOHDmisLAwtWjRQu7u7jxVCwDFWLNmjYYPH65nnnlG8+fPd3U5KCdCHozw2muv6ZVXXlF2drZ+97vfyc3NTQcPHnRs79ixoyZOnKiRI0eqcePGLqwUAFyvrH/Ynj59WuvXr9ddd92lRo0a1UBlqEqEPNR5R48eVadOndStWzetXLlS9erV0w033KC0tDR99dVX+vjjj5WQkCBJioyM1Pz583XLLbe4tmgAqEEXL17UiRMn1LJlS3l5eZXrvXy/bd1FyEOd99JLL2np0qX64IMPNHDgQElF/0rdv3+/XnvtNa1evVohISH617/+pe7du7uqZACoUa+++qo+/fRT/f73v1evXr0UGhqqG2644Zrh7cyZMwoICHCsRoC6h5CHOu/ee+9VYmKi4uPj1bJlS8caeHa7XTabzekktmjRIj3xxBMaO3asYmNjXVg1ANSc5s2bKzU1VW5ubvLz89Ntt92mqKgo9ezZU23atFFgYKBT/9zcXM2aNUtnz57VO++8w0xeHUU8R50XHh6uzz77TDk5OZLk+Kvz199XWziz95e//EXffPONNm/erCNHjqhNmzYuqxsAasKhQ4eUmZmp3r176/7779fXX3+tnTt3as2aNWrZsqX69++vQYMGKTw8XDfeeKP8/f114MABvfPOO+rfvz8Brw4j5KHOK/yy7AceeEALFy5U3759i137qfC+ktDQUK1bt84RCgHAZIcOHdKlS5cUFRWlSZMm6c4779TBgwe1c+dObd68WZ9++qn+9a9/qWPHjhowYIDuuOMObdq0SVlZWRo/fryry0clcLkWdV5BQYGmTZum119/XWFhYZo0aZJGjhypG264oUjfc+fOaerUqVq3bp1++eUXF1QLADXrk08+0ahRo7Rq1SqNGjXK0Z6Xl6fjx49r7969+uabbxxriXp4eMhut8vT01MZGRkurByVRciDMZYuXaoFCxboyJEjatasmUaMGKEhQ4aoRYsWcnNzk7+/v95++229+eabmjhxohYuXOjqkgGg2tntdv3000+qX7++WrduXezyKbm5uTp06JAOHjyo2NhYff3115o8ebLeeustF1WNqkDIgzHsdrsOHz6sd955R6tWrXJ8uXbjxo3l4eGhU6dOyWaz6b777tP8+fPVvHlzF1cMAK5VXOCbMmWKFi9erD179ig8PNxFlaEqEPJgpNzcXO3evVtffvmlUlNT9csvv8jX11ejRo3Svffeq/r167u6RACoNWw2m6xWq44dO6a7775b586d04kTJ1xdFiqJBy9gJG9vb0VGRioyMlJ5eXny8PBwdUkAUGtZrVZJ0smTJ5WXl6eJEye6uCJUBWbyAACApKuXb1NSUtSoUSN5e3u7uhxUEiEPAADAQFZXFwAAAICqR8gDAAAwECEPAADAQIQ8AAAAAxHyAAAADETIAwAAMBAhDwAAwECEPAAAAAMR8gAAAAz0/wFidBJdz1fojgAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHWCAYAAAD6oMSKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAJcNJREFUeJzt3QmQVdWdP/Bfs8iiIpuKREUxCqIgRqNxjSgBkWjcMsYh7qORUsclGsNEUXAdTaI1KZfEiTpWNEad0RhicN8C7o7R6GghwYAKyhIWUVn7X+fMv980SCMQmn59/Hyqbr1+595+fe/rvre/72y3pra2tjYAAGj2WjT1DgAAsHYIdgAAhRDsAAAKIdgBABRCsAMAKIRgBwBQCMEOAKAQgh0AQCFaNfUOVKulS5fG+++/HxtuuGHU1NQ09e4AAF9QtbW1MW/evOjevXu0aLHyOjnBrgEp1G2xxRaN8fsBAFhtU6ZMic0333yl2wh2DUg1dXVvYocOHVb/3QcAWAvmzp2bK5vqssnKCHYNqGt+TaFOsAMAmtqqdA0zeAIAoBCCHQBAIQQ7AIBCCHZUrYsvvjj3J6i/9O7dO6+bNWtWnHHGGdGrV69o165dbLnllvHP//zPMWfOnBW+1syZM/NIovQas2fPXsdHAgDrhsETVLUddtghHnnkkcrzVq1aVaajScuPf/zj6NOnT/z1r3+NU089NZfdc889n3mdk046Kfr16xfvvffeOt1/AFiXBDuqWgpy3bp1+0z5jjvuGP/5n/9Zeb7NNtvEZZddFt/97ndj8eLFlQCY3HDDDbmWbuTIkfGHP/xhne07AKxrmmKpahMmTMgzbffs2TOGDRsWkydPbnDb1AybpqapH+reeOONGD16dNx2222fO1s3ADR3/tNRtXbfffe49dZbY+zYsbnWbdKkSbHPPvvk26osb8aMGXHJJZfEKaecUilbsGBBHH300XH11VfnPngAUDpNsVStIUOGVL5O/eNS0OvRo0fcdddduc9c/Rm5hw4dmvvapQEXdUaMGBHbb799bp4FgC8CNXY0Gx07doztttsu3n777UpZqr078MAD821W7r333mjdunVl3WOPPRZ33313bppNywEHHJDLu3btGhdddFGTHAMANCY1djQbH330UUycODGOOeaYSk3d4MGDo02bNnH//fdH27Ztl9k+Da745JNPKs9feOGFOPHEE+Ppp5/Ogy0AoDSCHVXr3HPPjYMPPjg3v6ZpTFItW8uWLXO/uRTqBg0aFB9//HH86le/ys/Tkmy88cZ5u+XDW+qHl6Tm2VT7BwClEeyoWu+++24OcWly4RTW9t5773j22Wfz10888UQ899xzebsvf/nLy3xfGmSx1VZbNdFeA0DTqamtra31C/isVPuz0UYbVabQAACo9kxi8AQAQCEEOwCAQgh2AACFEOwAAAoh2AEAFEKwAwAohGAHAFAIwQ4ACnDxxRdHTU3NMkvv3r0r6z/99NM47bTTokuXLrHBBhvEEUccER988MEyrzF58uQYOnRotG/fPjbZZJM477zzYvHixU1wNKwpd54AgELssMMO8cgjj1Set2r1f//mzz777Pj9738fd999d57s9vTTT4/DDz88xo0bl9cvWbIkh7pu3brF+PHjY+rUqXHsscdG69at4/LLL2+S42H1CXYAUIgU5FIwW166Y8Evf/nLuOOOO2L//ffPZbfccku+d3a6VePXvva1eOihh+KNN97IwXDTTTeN/v37xyWXXBLnn39+rg1cb731muCIWF2aYgGgEBMmTIju3btHz549Y9iwYblpNXnppZdi0aJFMXDgwMq2qZl2yy23jGeeeSY/T499+/bNoa7O4MGD8+2sXn/99SY4GtaEYAcABdh9993j1ltvjbFjx8YNN9wQkyZNin322SfmzZsX06ZNyzVuHTt2XOZ7UohL65L0WD/U1a2vW0fzoCkWAAowZMiQytf9+vXLQa9Hjx5x1113Rbt27Zp031h31NgBQIFS7dx2220Xb7/9du53t3Dhwpg9e/Yy26RRsXV98tLj8qNk656vqN8e1UmwA4ACffTRRzFx4sTYbLPNYpdddsmjWx999NHK+rfeeiv3wdtjjz3y8/T42muvxYcffljZ5uGHH44OHTpEnz59muQYWH2aYgGgAOeee24cfPDBufn1/fffj4suuihatmwZRx99dJ7e5KSTTopzzjknOnfunMPaGWeckcNcGhGbDBo0KAe4Y445Jq666qrcr+6CCy7Ic9+1adOmqQ+PVSTYAUAB3n333RziZs6cGRtvvHHsvffeeSqT9HVyzTXXRIsWLfLExAsWLMgjXq+//vrK96cQOGbMmBg+fHgOfOuvv34cd9xxMXr06CY8KlZXTW1tbe1qf9cXQBre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eDz00EMxePDgePbZZ6NPnz5rd68BAFh7wW706NGxcOHCeOCBB+LAAw9cZt35558fY8eOjUMOOSRvd+edd67pjwEAoLEHT6RRsUceeeRnQl2dVJ7Wp9o7AACqONjNmTMntt5665Vuk9an7QAAqOJg171799x/bmWee+65vB0AAFUc7FL/udQce+GFF8ann366zLr0/KKLLsrNsN/61rfWxn4CANBYgydSoBszZkxcfvnl8fOf/zx222232HTTTeODDz6IF154IaZPnx49e/bM2wEAUMXBrkuXLrkp9gc/+EEe9ZpGx9Zp27Ztnt/uX//1X6Nz585ra18BAGisCYq7du0aN998c66xe/PNNyt3nujdu3e0bt3673lpAAAaO9hddtllMX/+/Bg1alQlvKXHvn37VrZJ89v96Ec/ig033DB++MMfru6PAACgsQdPPPLIIzFy5MjcDLuyGrn11lsvb5PCnXnsAACqMNjddttt0alTpzj99NM/d9vTTjst969L94sFAKDKgt348eNj4MCB0aZNm8/dNm2Tth03btzfs38AADRGsHv//ffzFCarKt15YurUqavzIwAAWBfBrkWLFrFo0aJV3j5tm74HAIDGt1qpK90e7M9//vMqb5+2/dKXvrQm+wUAQGMGu3322Scee+yxeOeddz5327RN2nbfffdd3X0CAKCxg10a6ZqaV4888siYMWNGg9vNnDkzvv3tb8fixYtj+PDha7JfAAA05gTFX/nKV+Kss86Ka6+9Nvr06ROnnnpqDBgwIDbffPO8/r333otHH300fvGLX+R7xZ5zzjn5ewAAqMI7T/zkJz/J94K9+uqr810o0lJfbW1ttGzZMkaMGBGXXnrp2txXAADWZrCrqamJyy+/PE466aQ8+XCa227atGl5Xbdu3WKvvfaK448/PrbZZpvVfWkAANZlsKuTgpsaOQCA6mGSOQCAQgh2AACFEOwAAAoh2AEAFEKwAwAohGAHAFAIwQ4AoBCCHQBAIQQ7AIBCCHYAAIUQ7AAACiHYAQAUQrADACiEYAcAUAjBDgCgEIIdAEAhBDsAgEIIdgAAhRDsAAAKIdgBABRCsAMAKIRgBwBQCMEOAKAQgh0AQCEEOwCAQgh2AACFEOwAAAoh2AEAFEKwAwAohGAHAFAIwQ4AoBCCHQBAIQQ7AIBCCHYAAIUQ7AAACiHYAQAU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zjvH1KlT44knnohTTjklXnvttdhqq62aepcBmlS6Lt55552xww47xKBBgyrlqaZu/PjxcfPNN+drarqeTp48OQ8+o/kQ7CjCggULYuLEifHkk0/Gb3/72/jjH/+YA9+XvvSlWLRoUQwbNixGjx7d1LsJUBU++eST/NiuXbsVDio799xz47HHHsszDdC8mO6EZmvGjBnxm9/8Jq6++urc1Nq5c+fo1KlT7uh73nnnxccffxx/+ctfYsiQIXnULABRCXR1lg91qUvLmDFj4oQTTvB2NUNq7Gi2TjzxxPjTn/6Ug9sGG2yQpz1J05u89957eXLi1Ok3dQ4G4P9q6uqHuoa2ueuuu+Loo4+uTPhO8yHY0SylpoMU5tJ8damjb11ZCnZPP/10/Pu//3ueo+mee+6JHXfcsal3F6AqfP/7388Tt6dRsN26dYs2bdp8ZpvZs2ebGqoZMyqWZumNN96Inj17xvrrr79Mc0Jqck01eWly4nTBSsEOgMjzfabJ2r/zne/kqaBGjBiR5/r88MMP85RQSZrz89hjj80jZWme1NjRLKWmgm9+85v5YpSG6KfRrsv3E/npT3+aL2Qvvvhik+0nQLX4p3/6p9y0mgZGpHnsUstGmgYqzSCQpo0aPHhwvPLKK3kWgTTojOZJjR3NUuojcumll+bh+Mccc0wOcGkIf91IrzRKNt2JolevXk29qwBNLn0ITq0c6e476fFHP/pRTJo0KQe5XXfdNa688srYd99943vf+16+ptJ8qbGjWUtz011yySXxu9/9Lve523vvvXO/kQcffDC6du2aP5H269evqXcToMmlvnMffPBB/sCb7s6T7ihRv6Uj3Wkihbr//u//jp122qlJ95U1J9hRhNRHJA3Pv++++3JtXhowceSRR8b222/f1LsGUNWTvKeBZy1btoybbropT/Sepoqi+RLsKPJClW4xBsCqS/2S090n0jygNF+CHQCQB0ykmjsfjJs3wQ4AoBDaqwAACiHYAQAUQrADACiEYAcAUAjBDgCgEIIdAEAhBDsAgEIIdgAAhRDsAACiDP8PRHu4dJBQF4wAAAAASUVORK5CYII=", "text/plain": [ - "
" + "
" ] }, - "execution_count": 9, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -140,7 +140,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "venv (3.14.2)", "language": "python", "name": "python3" }, @@ -154,7 +154,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.14.2" } }, "nbformat": 4, diff --git a/tests/test_notebooks.py b/tests/test_notebooks.py index 85cd5cb..7cc99c6 100644 --- a/tests/test_notebooks.py +++ b/tests/test_notebooks.py @@ -1,31 +1,141 @@ +"""Integration tests for Jupyter notebooks. + +This module executes all Jupyter notebooks in the repository to ensure they +run without errors. Tests require the IONQ_API_KEY environment variable to be +set for notebooks that make calls to IonQ's cloud APIs. +""" + import glob +import os import subprocess +import sys +import time + +import pytest + +NOTEBOOK_TIMEOUT_SECONDS = int(os.getenv("NBEXEC_TIMEOUT_SECONDS", "600")) +IONQ_API_KEY = os.getenv("IONQ_API_KEY") + + +def _run_notebook(path: str) -> None: + """Execute a notebook using nbconvert and fail with useful output on error. + Args: + path: Path to the Jupyter notebook file to execute. -def test_notebook(path): - # Run the notebook - res = subprocess.run( - ["python3", "-m", "nbconvert", "--to", "html", "--execute", path], + Raises: + AssertionError: If the notebook execution fails. + """ + print(f"\n{'='*60}") + print(f"Executing: {path}") + print(f"Timeout: {NOTEBOOK_TIMEOUT_SECONDS}s") + print(f"{'='*60}") + + start_time = time.time() + + cmd = [ + sys.executable, + "-m", + "jupyter", + "nbconvert", + "--to", + "html", + "--execute", + f"--ExecutePreprocessor.timeout={NOTEBOOK_TIMEOUT_SECONDS}", + path, + ] + + print(f"Running command: {' '.join(cmd)}") + print(f"Starting execution at {time.strftime('%Y-%m-%d %H:%M:%S')}") + + result = subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + text=True, ) - # If the notebook ran without errors, the return code will be 0 - if res.returncode != 0: - raise Exception( - f"Error executing the notebook {path}. Output:\n{res.stdout.decode('utf-8')} {res.stderr.decode('utf-8')}" + elapsed_time = time.time() - start_time + + if result.returncode != 0: + print(f"✗ FAILED after {elapsed_time:.2f}s") + print(f"\nSTDOUT:\n{result.stdout}") + print(f"\nSTDERR:\n{result.stderr}") + raise AssertionError( + f"Error executing notebook {path} after {elapsed_time:.2f}s.\n\n" + f"STDOUT:\n{result.stdout}\n\nSTDERR:\n{result.stderr}" ) + print(f"✓ PASSED in {elapsed_time:.2f}s") + print(f"Completed at {time.strftime('%Y-%m-%d %H:%M:%S')}") -def test_notebooks(): - # Get a list of all notebook files - notebooks = glob.glob("**/*.ipynb", recursive=True) - # Test each notebook +@pytest.mark.skipif( + not IONQ_API_KEY, + reason=( + "IONQ_API_KEY not set; skipping notebook execution tests that call " + "IonQ's cloud APIs." + ), +) +def test_notebooks() -> None: + """Execute all notebooks in the repository as an integration test. + + This test finds all .ipynb files recursively and executes them using + jupyter nbconvert. Each notebook must complete without errors. + + Raises: + AssertionError: If no notebooks are found or if any notebook fails. + """ + notebooks = sorted(glob.glob("**/*.ipynb", recursive=True)) + + print(f"\n{'='*60}") + print(f"Found {len(notebooks)} notebook(s) to test") + print(f"{'='*60}") + for i, nb in enumerate(notebooks, 1): + print(f"{i}. {nb}") + + assert notebooks, "No notebooks found to test." + + total_start = time.time() + passed = 0 + failed = 0 + for notebook in notebooks: - print(f"Testing {notebook}") - test_notebook(notebook) + try: + _run_notebook(notebook) + passed += 1 + except AssertionError as e: + failed += 1 + if not os.getenv("PYTEST_CURRENT_TEST"): + # Only re-raise if not running under pytest + raise + + total_elapsed = time.time() - total_start + + print(f"\n{'='*60}") + print(f"Test Summary") + print(f"{'='*60}") + print(f"Total notebooks: {len(notebooks)}") + print(f"✓ Passed: {passed}") + print(f"✗ Failed: {failed}") + print(f"Total time: {total_elapsed:.2f}s") + print(f"{'='*60}\n") + + if failed > 0: + raise AssertionError(f"{failed} notebook(s) failed to execute") if __name__ == "__main__": + print(f"\n{'='*60}") + print(f"Notebook Integration Test Runner") + print(f"{'='*60}") + print(f"Python version: {sys.version}") + print(f"Timeout per notebook: {NOTEBOOK_TIMEOUT_SECONDS}s") + print(f"API Key configured: {'Yes' if IONQ_API_KEY else 'No'}") + print(f"{'='*60}\n") + + if not IONQ_API_KEY: + print("⚠ IONQ_API_KEY not set; skipping notebook tests.") + raise SystemExit(0) + test_notebooks()