diff --git a/.github/workflows/build.yaml b/.github/workflows/python-package.yaml similarity index 97% rename from .github/workflows/build.yaml rename to .github/workflows/python-package.yaml index 9b2d941..cf9c3dc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/python-package.yaml @@ -3,8 +3,6 @@ name: python-tests on: push: branches: [main, py_wheel*] - release: - types: [published] jobs: newsynth: @@ -510,21 +508,3 @@ jobs: with: name: pyqret pattern: pyqret-* - - release: - if: github.event_name == 'release' - needs: [merge] - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Download merged artifact - uses: actions/download-artifact@v4 - with: - name: pyqret - path: dist - - - name: Upload artifact to release - uses: softprops/action-gh-release@v2 - with: - files: dist/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3e2b6a6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,376 @@ +name: qret-ci + +on: + push: + branches: [main] + paths: + - .github/workflows/release.yml + - CMakeLists.txt + - CMakePresets.json + - cmake/** + - quration-core/** + - quration-algorithm/** + - externals/** + - vcpkg.json + pull_request: + paths: + - .github/workflows/release.yml + - CMakeLists.txt + - CMakePresets.json + - cmake/** + - quration-core/** + - quration-algorithm/** + - externals/** + - vcpkg.json + release: + types: [published] + +jobs: + newsynth: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - macos-15-intel + - macos-latest + - windows-latest + - ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Restore newsynth cache + id: newsynth-cache + uses: actions/cache@v4 + with: + path: | + .newsynth/bin + .newsynth/license + key: newsynth-${{ matrix.os }}-v1 + + - name: Setup Haskell (GHC/Cabal) + if: steps.newsynth-cache.outputs.cache-hit != 'true' + uses: haskell-actions/setup@v2 + with: + ghc-version: "9.6.6" + cabal-version: "3.12.1.0" + + - name: Build newsynth binaries from Hackage + if: steps.newsynth-cache.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p "$PWD/.newsynth/bin" + cabal update + cabal install newsynth --installdir "$PWD/.newsynth/bin" --install-method=copy --overwrite-policy=always + if [ "$RUNNER_OS" != "Windows" ]; then + chmod +x "$PWD/.newsynth/bin/gridsynth" + fi + ls -la "$PWD/.newsynth/bin" + + - name: Download newsynth LICENSE files + if: steps.newsynth-cache.outputs.cache-hit != 'true' + shell: bash + run: | + rm -rf "$PWD/.newsynth/src" + rm -rf "$PWD/.newsynth/license" + mkdir -p "$PWD/.newsynth/src" + mkdir -p "$PWD/.newsynth/license" + cabal get newsynth --destdir "$PWD/.newsynth/src" --pristine + newsynth_src_dir=$(find "$PWD/.newsynth/src" -maxdepth 1 -type d -name "newsynth-*" | head -n 1) + if [ -n "$newsynth_src_dir" ]; then + find "$newsynth_src_dir" -maxdepth 2 -type f \ + \( -iname "LICENSE*" -o -iname "COPYING*" -o -iname "README*" -o -iname "GPL*" \) \ + -exec cp {} "$PWD/.newsynth/license/" \; + fi + ls -la "$PWD/.newsynth/license" + + build-qret: + needs: [newsynth] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: macos-15-intel + asset_suffix: macos-15-intel + archive_ext: tar.gz + - os: macos-latest + asset_suffix: macos-latest + archive_ext: tar.gz + - os: ubuntu-latest + asset_suffix: ubuntu-latest + archive_ext: tar.gz + - os: windows-latest + asset_suffix: windows-latest + archive_ext: zip + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Restore newsynth cache + uses: actions/cache@v4 + with: + path: | + .newsynth/bin + .newsynth/license + key: newsynth-${{ matrix.os }}-v1 + fail-on-cache-miss: true + + - name: Restore vcpkg cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/.vcpkg + ~/.cache/vcpkg + build/vcpkg_installed + key: vcpkg-${{ matrix.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-${{ matrix.os }}- + + - name: Restore ccache (Unix) + if: runner.os != 'Windows' + uses: actions/cache@v4 + with: + path: ~/.ccache + key: ccache-${{ matrix.os }}-${{ hashFiles('CMakeLists.txt', 'quration-core/src/**', 'quration-algorithm/src/**', 'quration-core/examples/**', 'quration-algorithm/examples/**') }} + restore-keys: | + ccache-${{ matrix.os }}- + + - name: Fix newsynth permissions (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + if [ -d "$PWD/.newsynth/bin" ]; then + chmod +x "$PWD"/.newsynth/bin/* || true + fi + + - name: Setup MSVC (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Configure vcpkg toolchain + shell: bash + run: | + mkdir -p "${{ github.workspace }}/.vcpkg" + echo "VCPKG_ROOT=${{ github.workspace }}/.vcpkg" >> "$GITHUB_ENV" + if [ ! -d "${{ github.workspace }}/.vcpkg/.git" ]; then + git clone https://github.com/microsoft/vcpkg.git "${{ github.workspace }}/.vcpkg" + fi + + - name: Install libyaml-cpp (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y build-essential gcc g++ libyaml-cpp0.8 libyaml-cpp-dev ccache + + - name: Set compiler env (Linux) + if: runner.os == 'Linux' + shell: bash + run: | + echo "CC=gcc" >> "$GITHUB_ENV" + echo "CXX=g++" >> "$GITHUB_ENV" + + - name: Install libyaml-cpp (macOS) + if: runner.os == 'macOS' + shell: bash + run: | + brew install yaml-cpp ccache + + - name: Configure Homebrew lib path (macOS) + if: runner.os == 'macOS' + shell: bash + run: | + brew_prefix=$(brew --prefix yaml-cpp) + if [ -n "$brew_prefix" ]; then + echo "DYLD_LIBRARY_PATH=$brew_prefix/lib:$DYLD_LIBRARY_PATH" >> "$GITHUB_ENV" + fi + + - name: Set compiler env (macOS) + if: runner.os == 'macOS' + shell: bash + run: | + echo "CC=clang" >> "$GITHUB_ENV" + echo "CXX=clang++" >> "$GITHUB_ENV" + + - name: Configure + shell: bash + run: | + launcher_args="" + if [ "${{ runner.os }}" != "Windows" ]; then + launcher_args="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" + ccache -s || true + fi + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DQRET_BUILD_ALGORITHM=ON \ + -DQRET_BUILD_EXAMPLE=ON \ + $launcher_args \ + -DCMAKE_TOOLCHAIN_FILE="${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" + + - name: Build qret and examples + shell: bash + run: | + cmake --build build --config Release + + - name: Show ccache stats (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + ccache -s || true + + - name: Install Python deps for example smoke tests + shell: bash + run: | + python -m pip install --upgrade pip + python -m pip install ortools + + - name: Install to stage + run: cmake --install build --config Release --prefix stage + + - name: Package artifact + shell: bash + run: | + mkdir -p dist package + root="qret-${{ matrix.asset_suffix }}" + package_root="package/$root" + mkdir -p "$package_root" + cp -R stage/. "$package_root/" + rm -rf "$package_root/include" + rm -rf "$package_root/lib/cmake" + + # Copy runtime resources used by installed example binaries. + mkdir -p "$package_root/quration-core/examples" + mkdir -p "$package_root/quration-algorithm/examples" + cp -R "$PWD/quration-core/examples/data" "$package_root/quration-core/examples/" + cp -R "$PWD/quration-core/examples/external-pass" "$package_root/quration-core/examples/" + cp -R "$PWD/quration-algorithm/examples/data" "$package_root/quration-algorithm/examples/" + + mkdir -p "$package_root/licenses/qret" + mkdir -p "$package_root/licenses/examples" + mkdir -p "$package_root/licenses/newsynth" + cp "$PWD/LICENSE" "$package_root/licenses/qret/LICENSE" + cp "$PWD/quration-algorithm/examples/LICENSE" "$package_root/licenses/examples/LICENSE" + + mkdir -p "$package_root/bin" + for file in "$PWD"/.newsynth/bin/*; do + [ -f "$file" ] || continue + base_name="$(basename "$file")" + case "$base_name" in + README*|readme*) + continue + ;; + esac + cp "$file" "$package_root/bin/" + done + + find "$PWD/.newsynth/license" -mindepth 1 -maxdepth 1 -type f -exec cp {} "$package_root/licenses/newsynth/" \; + + # Smoke-test every installed qret binary from inside the packaged tree. + pushd "$package_root" >/dev/null + if [ ! -d "quration-core" ]; then + echo "quration-core/ is required in the current working directory for example binaries." + exit 1 + fi + bin_ext="" + if [ "${{ runner.os }}" = "Windows" ]; then + bin_ext=".exe" + export PATH="$PWD/bin:$PWD/lib:$PWD/lib64:$PATH" + elif [ "${{ runner.os }}" = "macOS" ]; then + export DYLD_LIBRARY_PATH="$PWD/lib:$PWD/lib64:${DYLD_LIBRARY_PATH:-}" + else + export LD_LIBRARY_PATH="$PWD/lib:$PWD/lib64:${LD_LIBRARY_PATH:-}" + fi + mkdir -p _smoke_outputs + + run_bin() { + local name="$1" + shift + echo ">>> Running ${name}${bin_ext} $*" + "./bin/${name}${bin_ext}" "$@" + } + + run_bin qret --help + run_bin create_random + run_bin external_decompose_pass + run_bin external_mapping_pass + run_bin grover + run_bin portable_function + run_bin trotter \ + --file quration-core/examples/data/trotter/1d_ising_hamiltonian.json \ + --time 0.1 \ + --num_trotter_steps 1 \ + --out _smoke_outputs/core_trotter.json + + QRET_EXAMPLE_SMOKE=1 run_bin compile_adder_to_distributed_chip + run_bin create_add_craig + run_bin create_add_cuccaro + run_bin create_multi_controlled_mod_bi_mul_imm \ + --mod 15 \ + --imm 2 \ + --c 1 \ + --n 4 \ + --out _smoke_outputs/create_multi_controlled_mod_bi_mul_imm.json + run_bin create_period_finding \ + --mod 15 \ + --coprime 2 \ + --depth 4 \ + --out _smoke_outputs/create_period_finding.json + run_bin create_prepare \ + --file quration-algorithm/examples/data/sample_prepare.json \ + --out _smoke_outputs/create_prepare.json + run_bin create_qpe \ + --file quration-algorithm/examples/data/sample_qpe.json \ + --out _smoke_outputs/create_qpe.json + run_bin create_qrom + run_bin create_select \ + --file quration-algorithm/examples/data/sample_select.json \ + --out _smoke_outputs/create_select.json + run_bin create_trotter \ + --file quration-algorithm/examples/data/1d_ising_hamiltonian.json \ + --time 0.1 \ + --num_trotter_steps 1 \ + --out _smoke_outputs/create_trotter.json + run_bin create_uncompute_qrom + run_bin generate_quration_core_test_circuits _smoke_outputs/generated_circuits + run_bin qpe + run_bin shor + popd >/dev/null + + if [ "${{ runner.os }}" = "Windows" ]; then + python -c 'import shutil; from pathlib import Path; root = Path("package") / "qret-${{ matrix.asset_suffix }}"; out_base = Path("dist") / "qret-${{ matrix.asset_suffix }}"; shutil.make_archive(str(out_base), "zip", root_dir=root.parent, base_dir=root.name)' + else + tar -C package -czf "dist/$root.${{ matrix.archive_ext }}" "$root" + fi + + - name: Upload qret artifact + uses: actions/upload-artifact@v4 + with: + name: qret-${{ matrix.asset_suffix }} + path: dist/qret-${{ matrix.asset_suffix }}.${{ matrix.archive_ext }} + + release: + if: github.event_name == 'release' + needs: [build-qret] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download all qret artifacts + uses: actions/download-artifact@v4 + with: + path: dist + pattern: qret-* + merge-multiple: true + + - name: Upload artifacts to release + uses: softprops/action-gh-release@v2 + with: + files: dist/**/* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4dcf7c5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Quration Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index ac4a3bf..1db34ef 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,9 @@ The development of Quration is in progress, and their backward compatibility mig ## License +- Main `qret` build artifacts are distributed under MIT-license (`./LICENSE`). - External libraries (`./externals/`) are re-distributed under each library's license. -- Application generators (`./quration-algorithm/`) are distributed only for research purpose. +- Binaries under `./quration-algorithm/examples/` are unlicensed artifacts for research purpose (`./quration-algorithm/examples/LICENSE`). - The other quration libraries (`./quration-core/`, `./quration-visualize/`, `./quration-docs/`) are distributed under MIT-license. ## Features diff --git a/pyproject.toml b/pyproject.toml index 779ea5c..44f4f77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,13 @@ name = "pyqret" description = "Python wrapper of QRET" readme = "README.md" required-python = ">=3.10" +license = "MIT" # authors = # license = # keywords = classifiers = [ + "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/quration-algorithm/examples/LICENSE b/quration-algorithm/examples/LICENSE new file mode 100644 index 0000000..af41974 --- /dev/null +++ b/quration-algorithm/examples/LICENSE @@ -0,0 +1,20 @@ +Unlicensed + +The binaries under `quration-algorithm/examples` are distributed as +unlicensed artifacts for research usage only. + +Shipped example binaries covered by this notice: +- `compile_adder_to_distributed_chip` +- `create_add_craig` +- `create_add_cuccaro` +- `create_qrom` +- `create_uncompute_qrom` +- `generate_quration_core_test_circuits` +- `qpe` +- `shor` +- `create_trotter` +- `create_qpe` +- `create_prepare` +- `create_select` +- `create_period_finding` +- `create_multi_controlled_mod_bi_mul_imm` diff --git a/quration-algorithm/examples/compile_adder_to_distributed_chip.cpp b/quration-algorithm/examples/compile_adder_to_distributed_chip.cpp index 316331b..55bba67 100644 --- a/quration-algorithm/examples/compile_adder_to_distributed_chip.cpp +++ b/quration-algorithm/examples/compile_adder_to_distributed_chip.cpp @@ -13,7 +13,10 @@ #include "qret/target/sc_ls_fixed_v0/routing.h" #include "qret/target/sc_ls_fixed_v0/sc_ls_fixed_v0_target_machine.h" #include "qret/target/sc_ls_fixed_v0/topology.h" +#include "qret/transforms/ipo/inliner.h" #include "qret/transforms/scalar/decomposition.h" +#include +#include using namespace qret; using namespace qret::sc_ls_fixed_v0; @@ -29,6 +32,8 @@ void Run(const std::size_t size, const std::string& topology_path) { auto* circuit = gen.Generate(); auto* ir = circuit->GetIR(); ir::DecomposeInst().RunOnFunction(*ir); + // SC_LS_FIXED_V0 lowering rejects Call instructions; inline before lowering. + ir::RecursiveInlinerPass().RunOnFunction(*ir); auto topology = Topology::FromYAML(LoadFile(topology_path)); const auto target = ScLsFixedV0TargetMachine( @@ -79,11 +84,22 @@ int main() { ) ->SetValue(std::uint32_t{1}); - for (const auto size : {5, 10, 15, 20, 25, 30}) { + const auto smoke = std::getenv("QRET_EXAMPLE_SMOKE") != nullptr; + // Smoke mode keeps CI execution lightweight/stable while still executing this binary. + const auto sizes = smoke ? std::vector{5} + : std::vector{5, 10, 15, 20, 25, 30}; + + for (const auto size : sizes) { Run(size, "quration-core/examples/data/topology/dist_line.yaml"); Run(size, "quration-core/examples/data/topology/dist_circle.yaml"); Run(size, "quration-core/examples/data/topology/dist_all.yaml"); } + + if (smoke) { + // Skip heavy benchmark/json-dump section in CI smoke runs. + return 0; + } + std::get*>( OptionStorage::GetOptionStorage()->At("sc_ls_fixed_v0_dump_compile_info_to_json") ) diff --git a/quration-core/src/qret/transforms/scalar/static_condition_pruning.cpp b/quration-core/src/qret/transforms/scalar/static_condition_pruning.cpp index bd5f21f..a07ece0 100644 --- a/quration-core/src/qret/transforms/scalar/static_condition_pruning.cpp +++ b/quration-core/src/qret/transforms/scalar/static_condition_pruning.cpp @@ -267,8 +267,15 @@ bool PruneCondition(Function& func, std::mt19937_64& engine) { value_list.emplace_back(static_register[r.id] == RegisterState::True); } const auto value = BoolArrayAsInt(value_list); + // NOTE: Keep debug logging fmt-compatible across runner toolchains. + // Some fmt versions cannot format std::vector directly. + auto value_bits = std::string{}; + value_bits.reserve(value_list.size()); + for (const auto bit : value_list) { + value_bits.push_back(bit ? '1' : '0'); + } - LOG_DEBUG("value_list: {}", value_list); + LOG_DEBUG("value_list(bits): {}", value_bits); LOG_DEBUG("value: {}", value); auto* next_bb = tmp->GetCaseBB().contains(value) ? tmp->GetCaseBB().at(value)