From 1bb8fc0d483c202ea6a5fa08b097df513dee27e8 Mon Sep 17 00:00:00 2001 From: Stefano Grava Date: Thu, 20 Aug 2026 16:41:45 +0200 Subject: [PATCH 1/5] add pyproject how to install and basic pipeline --- .github/workflows/build.yml | 31 +++++++++++++++++++++++++++++++ .github/workflows/lint.yml | 19 +++++++++++++++++++ .gitignore | 8 ++++---- README.md | 22 ++++++++++++++++++++++ pyproject.toml | 25 +++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/lint.yml create mode 100644 pyproject.toml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..41b3748 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build + +on: + push: + branches: [main] + pull_request: + +jobs: + install-pip: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.10" + - name: Install with pip + run: | + python -m venv .venv + source .venv/bin/activate + pip install . + + install-uv: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v10 + - name: Install with uv + run: | + uv venv + source .venv/bin/activate + uv pip install . diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..dc406ae --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: Lint + +on: + push: + branches: [main] + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v10 + - name: Install ruff + run: uv tool install ruff + - name: ruff format --check + run: uv tool run ruff format --check . + - name: ruff check + run: uv tool run ruff check . diff --git a/.gitignore b/.gitignore index 83972fa..423d55d 100644 --- a/.gitignore +++ b/.gitignore @@ -85,7 +85,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -164,9 +164,6 @@ venv.bak/ # Rope project settings .ropeproject -# mkdocs documentation -/site - # mypy .mypy_cache/ .dmypy.json @@ -216,3 +213,6 @@ __marimo__/ # Streamlit .streamlit/secrets.toml + +# VSCode settings +.vscode/settings.json diff --git a/README.md b/README.md index 86fa95e..b96d880 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,25 @@ Over the course of **3 weeks**, you'll follow a guided learning journey desi - 🎤 Recognition during the official QoolQit launch webinar - ☁️ Complimentary Pasqal Cloud emulation credits upon completion + +**How to install** + +First, create and activate a virtual environment, then install the package. Examples below use `pip` and [`uv`](https://docs.astral.sh/uv/), but feel free to use your favorite package manager instead. + +With `pip`: + +```bash +python -m venv .venv +source .venv/bin/activate +pip install . +``` + +With `uv`: + +```bash +uv venv +source .venv/bin/activate +uv pip install . +``` + +This installs QoolQit 1.4 and Jupyter so you can run the exercise notebooks with `jupyter lab` or `jupyter notebook`. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..cd45624 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "qoolqit-beta-testing-program" +version = "0.1.0" +description = "Qoolqit Beta Testing Program" +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name = "Francesco Ferrulli", email = "francesco.ferrulli@pasqal.com" }, + { name = "Stefano Grava", email = "s.grava-ext@pasqal.com" }, + { name = "Vittorio Vitale", email = "vittorio.vitale@pasqal.com" }, +] +dependencies = [ + "qoolqit>=1.4.0", + "jupyter", +] + +[tool.setuptools] +packages = [] + +[project.optional-dependencies] +dev = ["ruff"] From b9a480076240bfd6a31748c73c68a64584d5dc9f Mon Sep 17 00:00:00 2001 From: Stefano Grava Date: Thu, 20 Aug 2026 16:49:09 +0200 Subject: [PATCH 2/5] pip setup-uv action version --- .github/workflows/build.yml | 2 +- .github/workflows/lint.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41b3748..bb1e819 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v10 + - uses: astral-sh/setup-uv@v10.0.1 - name: Install with uv run: | uv venv diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index dc406ae..941eba1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v10 + - uses: astral-sh/setup-uv@v10.0.1 - name: Install ruff run: uv tool install ruff - name: ruff format --check From 068ccd5494e5c32efb5649d4ac10cb895c2def01 Mon Sep 17 00:00:00 2001 From: Stefano Grava Date: Thu, 20 Aug 2026 16:59:50 +0200 Subject: [PATCH 3/5] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b96d880..732337f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -🚀 **Join the QoolQit Beta Testing Program!** +## 🚀 **Join the QoolQit Beta Testing Program!** Be among the first to explore QoolQit, Pasqal's new open-source, hardware-agnostic Python framework for quantum programming. QoolQit lets you focus on designing quantum experiments while abstracting away the complexities of the underlying hardware. @@ -19,7 +19,7 @@ Over the course of **3 weeks**, you'll follow a guided learning journey desi - 🎤 Recognition during the official QoolQit launch webinar - ☁️ Complimentary Pasqal Cloud emulation credits upon completion -**How to install** +### ⚙️ **How to install** First, create and activate a virtual environment, then install the package. Examples below use `pip` and [`uv`](https://docs.astral.sh/uv/), but feel free to use your favorite package manager instead. From 44e0e35aa790dcbe7cd2717157d97a5e60b3f055 Mon Sep 17 00:00:00 2001 From: Anton Quelle Date: Mon, 24 Aug 2026 09:05:08 +0200 Subject: [PATCH 4/5] added exercise --- .../module1_graphs_embedding_EXERCISES.ipynb | 298 ++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb diff --git a/Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb b/Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb new file mode 100644 index 0000000..9667d9f --- /dev/null +++ b/Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "713028f0", + "metadata": {}, + "source": [ + "# QoolQit Exercises — Module 1\n", + "## Graphs and Embedding\n", + "\n", + "Welcome to this hands-on introduction to **QoolQit**, the Python library for\n", + "algorithm development in the Rydberg analog model. Across four self-contained\n", + "modules you will learn all the building blocks of a QoolQit application, and\n", + "assemble them in a quantum application in the final module:\n", + "\n", + "| Module | Topic |\n", + "|--------|-------|\n", + "| 1 | Graphs and Embedding |\n", + "| 2 | Register, Drive and Quantum Programs |\n", + "| 3 | Compilation and Execution |\n", + "| 4 | Putting it all together: solving a QUBO |\n", + "\n", + "### In this module you will learn\n", + "- How to create graphs with the `DataGraph` class (pre-defined layouts,\n", + " random graphs, graphs from raw data)\n", + "- The difference between *abstract* graphs and graphs *with coordinates*\n", + "- How to give coordinates to an abstract graph.\n", + "\n", + "\n", + "> **How to use this notebook.** \n", + "> - Cells marked **✏️ Exercise** contain gaps\n", + "> indicated by `...` or `# TODO` — replace them with working code following\n", + "> the instructions. \n", + "> - Cells marked **✅ Check** verify your answer: run them\n", + "> after completing the exercise. Everything else is provided and runs as-is.\n", + "> A separate **solution notebook** will be published.\n", + ">\n", + "> **API note:** we use qoolqit version 1.4" + ] + }, + { + "cell_type": "markdown", + "id": "6226deb9", + "metadata": {}, + "source": [ + "## 1. The `DataGraph` class\n", + "\n", + "In QoolQit, problems and atom layouts are described by graphs. The\n", + "`DataGraph` class (a subclass of `networkx.Graph`) is the central data\n", + "structure: it can hold **connectivity** (edges), **coordinates** (positions\n", + "of the nodes in the plane), and node and edge **weights**." + ] + }, + { + "cell_type": "markdown", + "id": "f89ebcdc", + "metadata": {}, + "source": [ + "### ✏️ Exercise 1.1 — Pre-defined graph layouts\n", + "\n", + "Create and draw three graphs:\n", + "1. `g_line`: a **line** graph with 5 nodes;\n", + "2. `g_circle`: a **circle** graph with 6 nodes and `spacing=1.0`;\n", + "3. `g_square`: a **square** grid graph with `m=3` rows and `n=3` columns.\n", + "\n", + "Use each graph's `.draw()` method to visualize it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af9b7821", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: create the three graphs\n", + "g_line = ...\n", + "g_circle = ...\n", + "g_square = ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e506aeb8", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12, 4))\n", + "\n", + "# TODO: print the graphs on the subplots\n", + "# ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eca26aea", + "metadata": {}, + "outputs": [], + "source": [ + "# ✅ Check\n", + "assert g_line.number_of_nodes() == 5\n", + "assert g_circle.number_of_nodes() == 6\n", + "assert g_square.number_of_nodes() == 9\n", + "print(\"All three graphs look right!\")" + ] + }, + { + "cell_type": "markdown", + "id": "a9b0848c", + "metadata": {}, + "source": [ + "## 2. Abstract graphs vs. graphs with coordinates\n", + "\n", + "Not every graph has coordinates. What is required is only their connectivity: edges and nodes. \n", + "A **random Erdős–Rényi graph**, for\n", + "instance, is purely *abstract*: it defines which nodes are connected, but\n", + "says nothing about where the nodes sit in the plane. Since neutral atoms live\n", + "in real space, sooner or later every graph needs coordinates. That is the\n", + "job of *embedding* (Section 4).\n", + "\n", + "Useful properties to interrogate a graph: `has_coords`, `has_edges`,\n", + "`has_node_weights`, `has_edge_weights`." + ] + }, + { + "cell_type": "markdown", + "id": "e3ffa662", + "metadata": {}, + "source": [ + "### ✏️ Exercise 1.2 — An abstract random graph\n", + "\n", + "1. Create `g_er`, an Erdős–Rényi random graph with `n=8` nodes, edge\n", + " probability `p=0.4` and `seed=3` (for reproducibility).\n", + "2. Print whether it has coordinates (`has_coords`) and how many edges it has.\n", + "3. Try to compute `g_er.min_distance()` inside a `try/except Exception` block\n", + " and print the error — distances make no sense without coordinates!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61d92e10", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: create the random ER graph\n", + "g_er = ...\n", + "\n", + "print(\"Has coordinates:\", ...)\n", + "print(\"Number of edges:\", g_er.number_of_edges())\n", + "\n", + "try:\n", + " g_er.min_distance()\n", + "except AttributeError as err:\n", + " print(\"As expected, this fails:\", err)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "724d4d0a", + "metadata": {}, + "outputs": [], + "source": [ + "# ✅ Check\n", + "assert g_er.number_of_nodes() == 8\n", + "assert not g_er.has_coords, \"An ER graph should be abstract (no coordinates)\"\n", + "print(\"Correct — g_er is an abstract graph.\")" + ] + }, + { + "cell_type": "markdown", + "id": "2a2264fd", + "metadata": {}, + "source": [ + "## 3. Embedding: assign coordinates to an abstract graph or interaction matrix\n", + "\n", + "**Embedding** is the process of assigning coordinates to a graph. QoolQit can take an\n", + " abstract graph and return the same graph *with coordinates* or take a symmetric matrix of *desired interactions* and return a graph whose node positions physically realize them (next section).\n" + ] + }, + { + "cell_type": "markdown", + "id": "d7a6df28", + "metadata": {}, + "source": [ + "### ✏️ Exercise 1.4 — Spring-layout embedding of the random graph\n", + "\n", + "1. Import `SpringLayoutEmbedder` from `qoolqit.embedding` and instantiate it.\n", + "2. Embed the abstract graph `g_er` from Exercise 1.2 into `g_er_embedded`.\n", + "3. Verify the embedded graph now has coordinates, print its `min_distance()`,\n", + " and draw it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0314e34", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: instantiate the embedder and embed g_er\n", + "embedder = ...\n", + "g_er_embedded = ...\n", + "\n", + "print(\"Has coordinates:\", g_er_embedded.has_coords)\n", + "print(\"Minimum distance:\", g_er_embedded.min_distance())\n", + "g_er_embedded.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f8d3fcb", + "metadata": {}, + "outputs": [], + "source": [ + "# ✅ Check\n", + "assert g_er_embedded.has_coords, \"The embedded graph should have coordinates\"\n", + "print(\"Spring-layout embedding successful!\")" + ] + }, + { + "cell_type": "markdown", + "id": "de059158", + "metadata": {}, + "source": [ + "### ✏️ Exercise 1.5 — Embed a target interaction matrix\n", + "\n", + "1. Define the symmetric 3×3 target matrix\n", + " `M = [[0, 1, 0.3], [1, 0, 0.5], [0.3, 0.5, 0]]` as a NumPy array.\n", + "2. Instantiate an `InteractionEmbedder` (from `qoolqit.embedding`) and embed\n", + " `M` into `g_int`.\n", + "3. Draw `g_int`, then print its `interactions()` dictionary side by side with\n", + " the corresponding entries of `M`. How close did the embedder get?\n", + "\n", + "> 💡 The `interactions()` method computes $1/r^6$ for each pair of nodes from\n", + "> the coordinates." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b2d9b52", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "# TODO: define the target interaction matrix\n", + "M = np.array(...)\n", + "\n", + "# TODO: embed it\n", + "g_int = ...\n", + "\n", + "g_int.draw()\n", + "\n", + "for (i, j), J in g_int.interactions().items():\n", + " print(f\"pair ({i},{j}): J = {J:.4f} target M = {M[i, j]:.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "881fa9d1", + "metadata": {}, + "outputs": [], + "source": [ + "# ✅ Check — every realized interaction within 5% of its target\n", + "for (i, j), J in g_int.interactions().items():\n", + " assert abs(J - M[i, j]) < 0.05, f\"pair ({i},{j}) is off: {J} vs {M[i, j]}\"\n", + "print(\"Interaction embedding matches the target matrix!\")" + ] + }, + { + "cell_type": "markdown", + "id": "f8f2abe6", + "metadata": {}, + "source": [ + "### Next module\n", + "Graphs describe *data* and *geometry*. In **Module 2** we turn geometry into\n", + "physics: the `Register` of atoms, the time-dependent `Drive`, and the\n", + "`QuantumProgram` that combines them." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From d5d1fb621258926237ca4a77472ba9c32c6db398 Mon Sep 17 00:00:00 2001 From: Anton Quelle Date: Mon, 24 Aug 2026 09:06:30 +0200 Subject: [PATCH 5/5] change folder structure --- .../module1_graphs_embedding_EXERCISES.ipynb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {Beta_testing_campaign/exercises => exercises}/module1_graphs_embedding_EXERCISES.ipynb (100%) diff --git a/Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb b/exercises/module1_graphs_embedding_EXERCISES.ipynb similarity index 100% rename from Beta_testing_campaign/exercises/module1_graphs_embedding_EXERCISES.ipynb rename to exercises/module1_graphs_embedding_EXERCISES.ipynb