Skip to content

Commit 58626b8

Browse files
YingrongChenCopilot
andcommitted
Merge alias sampling / QROM state prep (#621) into the SOSSA branch
Brings feature/cyr/sossa up to yingrongchen-alias-sampling-qrom-state-prep at 3e6053e, so #539 can be retargeted onto #621 and reviewed as the incremental SOSSA diff rather than as SOSSA plus all of alias sampling. The previous merge (ca88541) captured 4ab6221; the alias branch has moved 42 commits since, including two merges of main. Two conflicts, both add/add registration lists, both resolved as unions: - controlled_circuit_mapper/__init__.py: each side added a different mapper import and its __all__ entries. Kept both; __all__ is exactly the nine imported names. - registry.py: each side registered a different mapper. Kept both, preserving each side's relative order, since registration order is load-bearing here (DensePureStatePreparation must precede SparseIsometryStatePreparation). Two further breakages had NO conflict markers and would have shipped silently had the merge been trusted at face value: - PhaseGradient.qs: #621 deleted MakePhaseGradientAncillaPrep in ef8f189 under a "Dead code" heading. It is dead on that branch but live on this one: sossa_mapper.get_ancilla_prep_op calls it, and SOSSAWalk.qs imports it. Git took the deletion cleanly because this side never touched that region. Restored verbatim, with a note recording why it must stay. - PrepSelPrep.qs: #621 changed PrepSelPrep's 4th parameter from ancillaRegister to prepareRegister and added numSelectQubits, because an alias-sampling PREPARE register is wider than the select index. PSPWalk on this side still called it with four arguments. PSPWalk keeps its own arity, since MakeControlledPSPWalkOp and TestPSPWalkOnBasisState both depend on it; only its two internal calls pass the new argument, as Length(ancillaRegister), which is what merge-base computed as numAncillaQubits and so preserves the previous semantics exactly. Verified: Q# project compiles; all 57 distinct QSHARP_UTILS.<ns>.<name> references from Python resolve against the compiled context, with the checker calibrated in both directions; ruff check and ruff format clean over 326 files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2 parents ca88541 + 3e6053e commit 58626b8

110 files changed

Lines changed: 8052 additions & 1202 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/Dockerfile

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ RUN apt-get update && apt-get install -y locales && \
1111
ENV LANG=en_US.UTF-8 \
1212
LANGUAGE=en_US:en \
1313
LC_ALL=en_US.UTF-8 \
14-
QDK_UARCH=native \
15-
LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH} \
14+
LD_LIBRARY_PATH=/usr/local/lib \
1615
PATH=/usr/local/bin:${PATH}
1716

1817
# Create a non-root user with sudo privileges
@@ -31,6 +30,7 @@ RUN apt-get update && \
3130
gnupg \
3231
build-essential \
3332
cmake \
33+
ccache \
3434
clang \
3535
pkg-config \
3636
python3 \
@@ -45,7 +45,6 @@ RUN apt-get update && \
4545
libgtest-dev \
4646
libgmock-dev \
4747
libfmt-dev \
48-
libecpint-dev \
4948
ninja-build \
5049
gcovr \
5150
patchelf \
@@ -54,6 +53,11 @@ RUN apt-get update && \
5453
&& apt-get clean \
5554
&& rm -rf /var/lib/apt/lists/*
5655

56+
# Install the memory-/core-aware build parallelism helper. It is used during
57+
# dependency installation and may also be sourced by development scripts and
58+
# interactive shells.
59+
COPY .devcontainer/scripts/parallelism.sh /usr/local/share/qdk/parallelism.sh
60+
5761
# Install C++ dependencies
5862
COPY .devcontainer/scripts/install_cpp_dependencies.sh /tmp/install_cpp_dependencies.sh
5963
COPY cpp/manifest/qdk-chemistry/cgmanifest.json /tmp/cpp_cgmanifest.json
@@ -62,7 +66,7 @@ COPY external/macis/manifest/cgmanifest.json /tmp/macis_cgmanifest.json
6266
# Delete build directory after installation
6367
ENV KEEP_BUILD_DIR=0
6468
RUN bash /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json && \
65-
rm /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json
69+
rm /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json
6670

6771
# Create/align the non-root user and group (safe for repeated builds)
6872
RUN if getent group "$USER_GID" >/dev/null; then \
@@ -89,3 +93,38 @@ USER $USERNAME
8993

9094
# Setup bash prompt
9195
RUN echo 'export PS1="\[\033[1;34m\]\u@qdk-dev:\w$ \[\033[0m\]"' >> ~/.bashrc
96+
97+
# Use Microsoft's public package proxies by default. Override these build
98+
# arguments to use different registries.
99+
ARG NPM_CONFIG_REGISTRY=https://packagefeedproxy.microsoft.io/npm/
100+
ENV NPM_CONFIG_REGISTRY=${NPM_CONFIG_REGISTRY}
101+
102+
ARG PIP_INDEX_URL=https://packagefeedproxy.microsoft.io/pypi/simple
103+
ENV PIP_INDEX_URL=${PIP_INDEX_URL}
104+
105+
# Create the Python virtual environment.
106+
ENV VIRTUAL_ENV=/home/$USERNAME/qdk_chemistry_venv \
107+
PATH=/home/$USERNAME/qdk_chemistry_venv/bin:$PATH
108+
109+
# The post-create editable install disables build isolation so its persistent
110+
# CMake cache uses stable tool paths. Preinstall python/pyproject.toml's
111+
# [build-system].requires here; --check-build-dependencies detects any drift.
112+
RUN python -m venv "$VIRTUAL_ENV" \
113+
&& python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
114+
&& python -m pip install --no-cache-dir \
115+
"scikit-build-core>=0.10.0" \
116+
"pybind11>=2.13.6" \
117+
"numpy>=2.0.0,<2.4.0" \
118+
&& echo "source $VIRTUAL_ENV/bin/activate" >> ~/.bashrc
119+
120+
# Set the safe CMAKE_BUILD_PARALLEL_LEVEL for interactive shells
121+
RUN echo "source /usr/local/share/qdk/parallelism.sh" >> ~/.bashrc
122+
123+
# Set ENV variables for the container environment.
124+
# Override in shell (per-session) or devcontainer.json (persistent), if needed.
125+
# CMAKE_PREFIX_PATH - Make user-local C++ installations discoverable
126+
# QDK_UARCH - default to native architecture for QDK builds
127+
# CMAKE_BUILD_TYPE - default CMake build type
128+
ENV CMAKE_PREFIX_PATH=/home/$USERNAME/.local \
129+
QDK_UARCH=native \
130+
CMAKE_BUILD_TYPE=RelWithDebInfo
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"features": {
3+
"ghcr.io/devcontainers/features/git:1": {
4+
"version": "1.3.8",
5+
"resolved": "ghcr.io/devcontainers/features/git@sha256:fd75977de13a9979000e0e78baf949adb0ca71d2398995fa22e0a36d7e7e7fe2",
6+
"integrity": "sha256:fd75977de13a9979000e0e78baf949adb0ca71d2398995fa22e0a36d7e7e7fe2"
7+
},
8+
"ghcr.io/devcontainers/features/node:2": {
9+
"version": "2.1.0",
10+
"resolved": "ghcr.io/devcontainers/features/node@sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857",
11+
"integrity": "sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857"
12+
},
13+
"ghcr.io/devcontainers/features/rust:1": {
14+
"version": "1.5.1",
15+
"resolved": "ghcr.io/devcontainers/features/rust@sha256:f7afd923fd283db88ca961342ae65ea63a8c95bcf86e42c4c363f43bc4ba26a5",
16+
"integrity": "sha256:f7afd923fd283db88ca961342ae65ea63a8c95bcf86e42c4c363f43bc4ba26a5"
17+
}
18+
}
19+
}

.devcontainer/devcontainer.json

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,12 @@
2020
"ms-toolsai.jupyter"
2121
],
2222
"settings": {
23-
"python.defaultInterpreterPath": "/usr/local/bin/python",
24-
"python.formatting.provider": "none",
23+
"python.defaultInterpreterPath": "${containerEnv:VIRTUAL_ENV}/bin/python",
2524
"editor.formatOnSave": true,
2625
"editor.codeActionsOnSave": {
27-
"source.fixAll.ruff": true,
28-
"source.organizeImports.ruff": true
26+
"source.fixAll.ruff": "explicit",
27+
"source.organizeImports.ruff": "explicit"
2928
},
30-
"python.linting.enabled": true,
31-
"python.linting.lintOnSave": true,
3229
"[python]": {
3330
"editor.defaultFormatter": "charliermarsh.ruff",
3431
"editor.formatOnSave": true,
@@ -55,16 +52,25 @@
5552
"C_Cpp.codeAnalysis.clangTidy.runAutomatically": true,
5653
"C_Cpp.formatting": "clangFormat",
5754
"C_Cpp.clang_format_style": "file",
58-
"C_Cpp.clang_format_fallbackStyle": "Google"
55+
"C_Cpp.clang_format_fallbackStyle": "Google",
56+
"C_Cpp.default.cppStandard": "c++20",
57+
"cmake.buildType": "RelWithDebInfo"
5958
}
6059
}
6160
},
6261
"features": {
63-
"ghcr.io/devcontainers/features/git:1": {}
62+
"ghcr.io/devcontainers/features/git:1": {},
63+
"ghcr.io/devcontainers/features/node:2": {
64+
"version": "lts"
65+
},
66+
"ghcr.io/devcontainers/features/rust:1": {
67+
"version": "stable",
68+
"profile": "default"
69+
}
6470
},
6571
"remoteEnv": {
66-
"CPATH": "${containerEnv:CPATH}:/usr/include/hdf5/serial:/usr/include/eigen3"
72+
"CPATH": "/usr/include/hdf5/serial:/usr/include/eigen3"
6773
},
68-
"postCreateCommand": "bash .devcontainer/scripts/venv.sh",
74+
"postCreateCommand": "bash .devcontainer/scripts/post_create.sh",
6975
"remoteUser": "vscode"
7076
}

.devcontainer/scripts/install_cpp_dependencies.sh

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,30 @@ BUILD_DIR="${BUILD_DIR:-/tmp/qdk_deps_build}"
3737
INSTALL_PREFIX="${INSTALL_PREFIX:-/usr/local}"
3838
BUILD_TYPE="${BUILD_TYPE:-Release}"
3939
BUILD_SHARED_LIBS="${BUILD_SHARED_LIBS:-OFF}" # Default to static
40-
LIBINT_JOBS=${LIBINT_JOBS:-4} # Limit libint build jobs to 4 due to high memory usage
40+
4141
KEEP_BUILD_DIR="${KEEP_BUILD_DIR:-0}"
42-
if command -v nproc >/dev/null 2>&1; then
43-
JOBS=$(nproc) # Linux
42+
43+
PARALLELISM_HELPER="/usr/local/share/qdk/parallelism.sh"
44+
if [ -f "$PARALLELISM_HELPER" ]; then
45+
# shellcheck source=/dev/null
46+
source "$PARALLELISM_HELPER"
47+
fi
48+
49+
if command -v parallel_jobs_for_memory >/dev/null 2>&1; then
50+
# Use the parallelism helper to determine job counts based on memory
51+
JOBS="${JOBS:-$(parallel_jobs_for_memory 1)}"
52+
LIBINT_JOBS="${LIBINT_JOBS:-$(parallel_jobs_for_memory 4)}"
4453
else
45-
JOBS=$(sysctl -n hw.logicalcpu) # macOS
54+
# Fallback when helper is unavailable
55+
if command -v nproc >/dev/null 2>&1; then
56+
DEFAULT_JOBS=$(nproc) # Linux
57+
else
58+
DEFAULT_JOBS=$(sysctl -n hw.logicalcpu) # macOS
59+
fi
60+
JOBS="${JOBS:-$DEFAULT_JOBS}"
61+
LIBINT_JOBS="${LIBINT_JOBS:-4}"
4662
fi
63+
4764
MAC_BUILD="OFF"
4865
if [[ "$OSTYPE" == "darwin"* ]]; then
4966
MAC_BUILD="ON"
@@ -224,7 +241,6 @@ cmake .. -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
224241
-DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \
225242
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
226243
-DBUILD_SHARED_LIBS="$BUILD_SHARED_LIBS"
227-
# libint's compilation is memory intensive so parallel jobs are limited to 4 to prevent OOM errors
228244
make -j"$LIBINT_JOBS"
229245
make install
230246
cd "$BUILD_DIR"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# shellcheck shell=bash
2+
#
3+
# This file is intended to be sourced.
4+
#
5+
# It provides:
6+
# - parallel_jobs_for_memory()
7+
# - a default CMAKE_BUILD_PARALLEL_LEVEL (unless already set)
8+
#
9+
# parallel_jobs_for_memory <memory_per_job_gb>
10+
#
11+
# Compute a safe parallel job count based on available RAM and CPU cores.
12+
#
13+
# Result:
14+
# min(cpu_cores, floor(total_ram_gb / memory_per_job_gb))
15+
#
16+
# with a minimum value of 1.
17+
#
18+
parallel_jobs_for_memory() {
19+
local memory_per_job_gb="$1"
20+
local cores mem_bytes jobs
21+
22+
if [ -r /proc/meminfo ] && command -v nproc >/dev/null 2>&1; then
23+
# Linux
24+
cores=$(nproc)
25+
mem_bytes=$(awk '/MemTotal/ {print $2 * 1024}' /proc/meminfo)
26+
else
27+
# macOS (or other non-/proc environments)
28+
cores=$(sysctl -n hw.logicalcpu)
29+
mem_bytes=$(sysctl -n hw.memsize)
30+
fi
31+
32+
# If running inside a cgroup with a memory limit, respect it.
33+
local cgroup_limit_bytes=""
34+
if [ -r /sys/fs/cgroup/memory.max ]; then
35+
cgroup_limit_bytes="$(cat /sys/fs/cgroup/memory.max)" # cgroup v2
36+
elif [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
37+
cgroup_limit_bytes="$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" # cgroup v1
38+
fi
39+
if [[ "$cgroup_limit_bytes" =~ ^[0-9]+$ ]] && (( cgroup_limit_bytes > 0 )) && (( cgroup_limit_bytes < mem_bytes )); then
40+
mem_bytes="$cgroup_limit_bytes"
41+
fi
42+
43+
jobs=$(( mem_bytes / (memory_per_job_gb * 1024 * 1024 * 1024) ))
44+
45+
(( jobs < 1 )) && jobs=1
46+
(( jobs > cores )) && jobs=$cores
47+
48+
echo "$jobs"
49+
}
50+
51+
if [ -z "${CMAKE_BUILD_PARALLEL_LEVEL:-}" ]; then
52+
export CMAKE_BUILD_PARALLEL_LEVEL="$(parallel_jobs_for_memory 8)"
53+
fi
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
# Post-create step: install QDK Chemistry from the mounted source.
3+
set -euo pipefail
4+
source "${VIRTUAL_ENV:?}/bin/activate"
5+
6+
# Set a memory-/core-aware CMAKE_BUILD_PARALLEL_LEVEL (unless already set) so the
7+
# initial build below does not oversubscribe CPU or OOM on constrained machines.
8+
source /usr/local/share/qdk/parallelism.sh
9+
10+
# Build C++ and install to a user-local prefix.
11+
# Use the in-tree macis (external/macis) per INSTALL.md; prevents a
12+
# full rebuild on reconfigure.
13+
cmake -S cpp -B cpp/build -G Ninja \
14+
-DCMAKE_INSTALL_PREFIX="$HOME/.local" \
15+
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:-RelWithDebInfo}" \
16+
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
17+
-DCMAKE_DISABLE_FIND_PACKAGE_macis=ON
18+
cmake --build cpp/build
19+
cmake --install cpp/build
20+
21+
# Install python library
22+
cd ./python
23+
pip install -v \
24+
--no-build-isolation \
25+
--check-build-dependencies \
26+
-C build-dir="build/{wheel_tag}" \
27+
-e '.[all]'

.devcontainer/scripts/venv.sh

Lines changed: 0 additions & 28 deletions
This file was deleted.

.github/skills/memory-aware-build/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ job. Limit build parallelism by both the available memory and the CPU count.
1919
including builds started indirectly by `pip`.
2020

2121
For example, a machine with 32 GB of available RAM and 16 logical CPUs should
22-
compile with at most six jobs:
22+
compile with at most four jobs:
2323

2424
```bash
25-
export CMAKE_BUILD_PARALLEL_LEVEL=6
25+
export CMAKE_BUILD_PARALLEL_LEVEL=4
2626
cmake --build cpp/build
2727
```
2828

2929
For a Python package build, apply the same limit:
3030

3131
```bash
32-
CMAKE_BUILD_PARALLEL_LEVEL=6 python -m pip install ./python
32+
CMAKE_BUILD_PARALLEL_LEVEL=4 python -m pip install ./python
3333
```
3434

3535
If a build is killed or reports an out-of-memory error, reduce

INSTALL.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,31 @@ Alternatively, click the green button in the bottom-left corner of VS Code and s
130130

131131
After the initial build, restart VS Code and reopen in the container to ensure the Python virtual environment is properly loaded.
132132

133+
### Step 4: Develop
134+
135+
The dev container installs the Python package in editable mode, so changes to pure Python files are available immediately. After changing pybind11 sources, rebuild the Python package:
136+
137+
```bash
138+
python -m pip install --no-build-isolation --check-build-dependencies --no-deps \
139+
-C build-dir="build/{wheel_tag}" -e ./python
140+
```
141+
142+
After changing the C++ library, build and install it before rebuilding the Python bindings:
143+
144+
```bash
145+
cmake --build cpp/build --target chemistry
146+
cmake --install cpp/build
147+
python -m pip install --no-build-isolation --check-build-dependencies --no-deps \
148+
-C build-dir="build/{wheel_tag}" -e ./python
149+
```
150+
151+
Build only the relevant C++ test target during development, then run its tests from the directory where CTest registers them. For example:
152+
153+
```bash
154+
cmake --build cpp/build --target test_algorithm_hash
155+
ctest --test-dir cpp/build/tests --output-on-failure -R AlgorithmHash
156+
```
157+
133158
**NOTE:**
134159

135160
- The first build can take up to two hours on slower systems.

0 commit comments

Comments
 (0)