From 3b53b3a1856024d127392295650ccbe65356493a Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 16:22:41 +0200 Subject: [PATCH 1/7] Update demo notebooks --- .../visualization/amplitude_components.ipynb | 5 +- demos/visualization/geometry.ipynb | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/demos/visualization/amplitude_components.ipynb b/demos/visualization/amplitude_components.ipynb index 3a299268..2c5b298e 100644 --- a/demos/visualization/amplitude_components.ipynb +++ b/demos/visualization/amplitude_components.ipynb @@ -17,11 +17,10 @@ "source": [ "# Import the required packages from the qlbm framework\n", "from qlbm.components import (\n", - " CQLBM,\n", " ABStreamingOperator,\n", " ControlledIncrementer,\n", " MSStreamingOperator,\n", - " SpeedSensitivePhaseShift,\n", + " ParameterizedPhaseShift,\n", ")\n", "from qlbm.components.ab import ABStreamingOperator\n", "from qlbm.lattice import ABLattice, MSLattice" @@ -61,7 +60,7 @@ "outputs": [], "source": [ "# Define an example which uses 4 velocity qubits and the qubits with speed 2 will stream\n", - "speed_shift_primitive = SpeedSensitivePhaseShift(5, 1, True)" + "speed_shift_primitive = ParameterizedPhaseShift(5, 1, True)" ] }, { diff --git a/demos/visualization/geometry.ipynb b/demos/visualization/geometry.ipynb index 20547788..5ff43a79 100644 --- a/demos/visualization/geometry.ipynb +++ b/demos/visualization/geometry.ipynb @@ -40,6 +40,9 @@ "metadata": {}, "outputs": [], "source": [ + "from qlbm.lattice.lattices.ab_lattice import ABLattice\n", + "\n", + "\n", "lattice_2d = MSLattice(\n", " {\n", " \"lattice\": {\n", @@ -73,6 +76,23 @@ " }\n", " ],\n", " }\n", + ")\n", + "\n", + "ab_lattice_2d = ABLattice(\n", + " {\n", + " \"lattice\": {\n", + " \"dim\": {\"x\": 64, \"y\": 256},\n", + " \"velocities\": \"d2q9\",\n", + " },\n", + " \"geometry\": [\n", + " {\n", + " \"shape\": \"ymonomial\",\n", + " \"comparator\": \"<=\",\n", + " \"exponent\": 2,\n", + " \"boundary\": \"bounceback\",\n", + " },\n", + " ],\n", + " }\n", ")" ] }, @@ -83,8 +103,10 @@ "outputs": [], "source": [ "root_directory_2d = \"qlbm-output/visualization-components-2d\"\n", + "root_directory_2d_monomial = \"qlbm-output/visualization-components-2d-monomial\"\n", "root_directory_3d = \"qlbm-output/visualization-components-3d\"\n", "create_directory_and_parents(root_directory_2d)\n", + "create_directory_and_parents(root_directory_2d_monomial)\n", "create_directory_and_parents(root_directory_3d)" ] }, @@ -98,6 +120,16 @@ "AmplitudeResult(lattice_2d, root_directory_2d).visualize_geometry()" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Will output seven 2D stl files under `qlbm-output/visualization-components-2d-monomial/paraview`\n", + "AmplitudeResult(ab_lattice_2d, root_directory_2d_monomial).visualize_geometry()" + ] + }, { "cell_type": "code", "execution_count": null, @@ -122,6 +154,25 @@ ").plot(cpos=\"xy\", show_scalar_bar=True, jupyter_backend=\"static\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pl = pv.Plotter()\n", + "mesh = pv.read(\n", + " [\n", + " f\"{root_directory_2d_monomial}/paraview/{fname}\"\n", + " for fname in listdir(f\"{root_directory_2d_monomial}/paraview\")\n", + " ]\n", + ").plot(show_scalar_bar=True, jupyter_backend=\"interactive\")\n", + "\n", + "# pl.add_mesh(mesh)\n", + "# pl.camera_position = \"xy\"\n", + "# pl.save_graphic(\"ymonomial.pdf\")" + ] + }, { "cell_type": "code", "execution_count": null, @@ -135,11 +186,18 @@ " ]\n", ").plot(show_scalar_bar=True, jupyter_backend=\"static\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "qlbm-cpu-venv", "language": "python", "name": "python3" }, @@ -153,7 +211,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.13.9" } }, "nbformat": 4, From bfeceff61f09c59c78b9df339dd04f4a73a6e746 Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 16:23:25 +0200 Subject: [PATCH 2/7] Remove doctest from workflow and build docs on every PR --- .github/workflows/docs.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 03640c7a..d2b38fd7 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -42,13 +42,7 @@ jobs: run: | python -m pip install -U .[cpu,dev,docs] - - name: Doctest - if: ${{ github.event_name == 'pull_request' && github.ref == 'refs/heads/main' }} - run: | - make -C docs doctest - - name: Build Docs - if: ${{ github.ref == 'refs/heads/main' }} run: | sphinx-build docs/source _build From c8472b2d9bcd24c0e5bc3bd7ac010dcae02c3a96 Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 23:41:22 +0200 Subject: [PATCH 3/7] Group velocities into 1 streaming step in MSQLBM --- qlbm/components/cqlbm.py | 4 +++- qlbm/components/ms/msqlbm.py | 11 +++++++-- qlbm/tools/utils.py | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/qlbm/components/cqlbm.py b/qlbm/components/cqlbm.py index ae785b67..c62875b6 100644 --- a/qlbm/components/cqlbm.py +++ b/qlbm/components/cqlbm.py @@ -81,7 +81,9 @@ def create_circuit(self): if isinstance(self.lattice, MSLattice): if self.use_agnostic_bcs: raise CircuitException("Agnostic BCs are not supported for the MSQLBM.") - return MSQLBM(cast(MSLattice, self.lattice), self.logger).circuit + return MSQLBM( + cast(MSLattice, self.lattice), group_velocities=True, logger=self.logger + ).circuit elif isinstance(self.lattice, ABLattice): return ABQLBM( cast(ABLattice, self.lattice), diff --git a/qlbm/components/ms/msqlbm.py b/qlbm/components/ms/msqlbm.py index 52b02b0a..35b5bb35 100644 --- a/qlbm/components/ms/msqlbm.py +++ b/qlbm/components/ms/msqlbm.py @@ -34,16 +34,19 @@ class MSQLBM(LBMAlgorithm): ========================= ====================================================================== :attr:`lattice` The :class:`.MSLattice` based on which the properties of the operator are inferred. :attr:`logger` The performance logger, by default ``getLogger("qlbm")``. + :attr:`group_velocities` Whether to group velocities into 1 streaming step in the CFL series. ========================= ====================================================================== """ def __init__( self, lattice: MSLattice, + group_velocities: bool = False, logger: Logger = getLogger("qlbm"), ) -> None: super().__init__(lattice, logger) self.lattice: MSLattice = lattice + self.group_velocities = group_velocities self.logger.info(f"Creating circuit {str(self)}...") circuit_creation_start_time = perf_counter_ns() @@ -55,8 +58,12 @@ def __init__( @override def create_circuit(self): # Assumes equal velocities in all dimensions - # ! TODO adapt to DnQm discretization - time_series = get_time_series(2 ** self.lattice.num_velocities[0].bit_length()) + time_series = get_time_series( + 2 ** self.lattice.num_velocities[0].bit_length(), + group_velocities=self.group_velocities, + ) + + print(time_series) circuit = QuantumCircuit( *self.lattice.registers, ) diff --git a/qlbm/tools/utils.py b/qlbm/tools/utils.py index 083a7d76..2338a73e 100644 --- a/qlbm/tools/utils.py +++ b/qlbm/tools/utils.py @@ -182,10 +182,50 @@ def is_two_pow(num: int) -> bool: return (num & (num - 1) == 0) and num != 0 +def greedy_grouping(schedule: List[List[int]]) -> List[List[int]]: + """ + Greedily groups schedule into maximally sized groups. + + This function is designed to be used with the ordered output of + get_time_series. Using this function with arbitrary schedules + might not give optimal groupings. + + Parameters + ---------- + schedule : List[List[int]] + The ouput of the cfl counter in get_time_series + + Returns + ------- + List[List[int]] + Maximally grouped schedule + """ + flattened_schedule = np.concatenate(schedule).tolist() + + groups = [] + current_group: List[int] = [] + seen = set() + + for mag in flattened_schedule: + if mag in seen: + groups.append(current_group) + current_group = [mag] + seen = {mag} + else: + current_group.append(mag) + seen.add(mag) + + if current_group: + groups.append(current_group) + + return groups + + def get_time_series( num_discrete_velocities: int, max_allowed_iters: int = 10000, tolerance: float = 1e-6, + group_velocities: bool = True, ) -> List[List[int]]: """ Compute a time series of the streaming velocities for a given number of discrete velocities. @@ -198,6 +238,8 @@ def get_time_series( The number of iterations before truncating the time series, by default 10000 tolerance : float, optional The level of precision required to truncate the time sries, by default 1e-6 + group_velocities : bool, optional + When True, runs greedy grouping before returning schedule Returns ------- @@ -256,6 +298,9 @@ def get_time_series( ): break + if group_velocities: + speed_controls = greedy_grouping(speed_controls) + return speed_controls # type: ignore From 85482df162c3bb94d9ec3dc398435d4fa371e17f Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 23:41:48 +0200 Subject: [PATCH 4/7] Update MSQLBM simulation demo --- demos/simulation/ms_simulation.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/simulation/ms_simulation.ipynb b/demos/simulation/ms_simulation.ipynb index 692e13ab..3f1aae9b 100644 --- a/demos/simulation/ms_simulation.ipynb +++ b/demos/simulation/ms_simulation.ipynb @@ -18,7 +18,7 @@ "from qiskit_aer import AerSimulator\n", "\n", "from qlbm.components import (\n", - " CQLBM,\n", + " MSQLBM,\n", " EmptyPrimitive,\n", " GridMeasurement,\n", " MSInitialConditions,\n", @@ -64,7 +64,7 @@ "source": [ "cfg = SimulationConfig(\n", " initial_conditions=MSInitialConditions(lattice),\n", - " algorithm=CQLBM(lattice),\n", + " algorithm=MSQLBM(lattice, group=True),\n", " postprocessing=EmptyPrimitive(lattice),\n", " measurement=GridMeasurement(lattice),\n", " target_platform=\"QISKIT\",\n", @@ -73,7 +73,7 @@ " statevector_sampling=True,\n", " execution_backend=AerSimulator(method=\"statevector\"),\n", " sampling_backend=AerSimulator(method=\"statevector\"),\n", - ")\n" + ")" ] }, { From acb29ff960a343393c64e7a1e03f6c905ffcb1ee Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 23:42:10 +0200 Subject: [PATCH 5/7] Update caching in tests workflow --- .github/workflows/tests.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 105e8a74..6db91e6e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,10 +29,20 @@ jobs: key: pip-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} restore-keys: | pip-${{ matrix.python-version }}- + - name: Cache apt packages + uses: actions/cache@v4 + id: cache-apt + with: + path: /var/cache/apt/archives + key: apt-${{ runner.os }}-libboost-cmake-${{ hashFiles('.github/workflows/tests.yml') }} + restore-keys: | + apt-${{ runner.os }}-libboost-cmake- - name: Install dependencies run: | - sudo apt-get update && sudo apt-get install -y -qq libboost-all-dev cmake + sudo apt-get update -qq + sudo apt-get install -y -qq libboost-all-dev cmake - name: Install qlbm + id: pip-install run: | pip install --upgrade pip pip install -e .[cpu,dev] From 3d14bcbc47ec8cfd6a4bf57042be3a167f5c82c1 Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Tue, 12 May 2026 23:42:10 +0200 Subject: [PATCH 6/7] Update caching in tests workflow --- .github/workflows/tests.yml | 12 +++++++++++- demos/simulation/ms_simulation.ipynb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 105e8a74..6db91e6e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,10 +29,20 @@ jobs: key: pip-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} restore-keys: | pip-${{ matrix.python-version }}- + - name: Cache apt packages + uses: actions/cache@v4 + id: cache-apt + with: + path: /var/cache/apt/archives + key: apt-${{ runner.os }}-libboost-cmake-${{ hashFiles('.github/workflows/tests.yml') }} + restore-keys: | + apt-${{ runner.os }}-libboost-cmake- - name: Install dependencies run: | - sudo apt-get update && sudo apt-get install -y -qq libboost-all-dev cmake + sudo apt-get update -qq + sudo apt-get install -y -qq libboost-all-dev cmake - name: Install qlbm + id: pip-install run: | pip install --upgrade pip pip install -e .[cpu,dev] diff --git a/demos/simulation/ms_simulation.ipynb b/demos/simulation/ms_simulation.ipynb index 3f1aae9b..2be82df3 100644 --- a/demos/simulation/ms_simulation.ipynb +++ b/demos/simulation/ms_simulation.ipynb @@ -64,7 +64,7 @@ "source": [ "cfg = SimulationConfig(\n", " initial_conditions=MSInitialConditions(lattice),\n", - " algorithm=MSQLBM(lattice, group=True),\n", + " algorithm=MSQLBM(lattice, group_velocities=True),\n", " postprocessing=EmptyPrimitive(lattice),\n", " measurement=GridMeasurement(lattice),\n", " target_platform=\"QISKIT\",\n", From 8a798f096c380bf06708e9c33d33f3b4406a9aa0 Mon Sep 17 00:00:00 2001 From: Calin Georgescu Date: Wed, 13 May 2026 00:17:17 +0200 Subject: [PATCH 7/7] Update test wokflow --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6db91e6e..880be822 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,6 +38,7 @@ jobs: restore-keys: | apt-${{ runner.os }}-libboost-cmake- - name: Install dependencies + if: steps.cache-apt.outputs.cache-hit != 'true' run: | sudo apt-get update -qq sudo apt-get install -y -qq libboost-all-dev cmake