Adding time-dependent Hamiltonian evolution #2094
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Test | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - '**' | |
| merge_group: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| checks: write | |
| statuses: write | |
| jobs: | |
| check-up-to-date: | |
| name: Check if branch is up to date with main | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: recursive | |
| - name: Check if branch is up to date with main (Pull Request) | |
| run: | | |
| # Ensure origin/main is present | |
| git fetch --no-tags --prune origin +refs/heads/main:refs/remotes/origin/main | |
| # Check if the current commit is ahead of main | |
| # Kills pipeline if branch is not up to date with main | |
| # For pull requests, we use github.event.pull_request.sha to get the commit SHA, | |
| # as GitHub treats the current commit as one that would be produced by merging into main | |
| if ! git merge-base --is-ancestor origin/main "${{ github.event.pull_request.head.sha }}"; then | |
| echo "This branch is not up to date with main. Please merge the latest changes from main into your branch to continue." | |
| exit 1 | |
| fi | |
| echo "Branch is up to date, starting Build and Test workflow." | |
| coverage: | |
| name: ${{ matrix.os-name }} Build, Test, and Coverage Analysis | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os-name: Linux | |
| runner: [self-hosted, 1ES.Pool=1es-gh-hb120-pool] | |
| build-parallel: 120 | |
| uarch: x86-64-v3 | |
| python-version: '3.10' | |
| cpp-test-threads: 2 | |
| python-test-threads: 2 | |
| - os-name: Linux | |
| runner: [self-hosted, 1ES.Pool=1es-gh-hb120-pool] | |
| build-parallel: 120 | |
| uarch: x86-64-v3 | |
| python-version: '3.13' | |
| cpp-test-threads: 2 | |
| python-test-threads: 2 | |
| - os-name: Linux | |
| runner: [self-hosted, 1ES.Pool=1es-gh-hb120-pool] | |
| build-parallel: 120 | |
| uarch: x86-64-v3 | |
| python-version: '3.14' | |
| # qiskit-extras is not supported on Python 3.14 | |
| skip-qiskit-extras: true | |
| cpp-test-threads: 2 | |
| python-test-threads: 2 | |
| - os-name: macOS | |
| runner: macos-26-xlarge | |
| build-parallel: 3 | |
| uarch: native | |
| python-version: '3.13' | |
| cpp-test-threads: 16 | |
| python-test-threads: 16 | |
| env: | |
| BUILD_DIR: cpp/build | |
| QSHARP_PYTHON_TELEMETRY: 'false' | |
| CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/install | |
| CPP_DEPS_PREFIX: ${{ github.workspace }}/cpp_deps_install | |
| CTEST_OUTPUT_ON_FAILURE: 1 | |
| CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.build-parallel }} | |
| QDK_UARCH: ${{ matrix.uarch }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up environment paths | |
| run: | | |
| echo "PATH=${{ github.workspace }}/install/bin:${{ github.workspace }}/install/lib:$PATH" >> $GITHUB_ENV | |
| echo "PYTHONPATH=${{ github.workspace }}/install/lib/python${{ matrix.python-version }}/site-packages:${{ github.workspace }}/install/lib:$PYTHONPATH" >> $GITHUB_ENV | |
| echo "LD_LIBRARY_PATH=${{ github.workspace }}/install/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| - name: Install Linux system packages | |
| if: matrix.os-name == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| ninja-build \ | |
| cmake \ | |
| libeigen3-dev \ | |
| libboost-all-dev \ | |
| libhdf5-dev \ | |
| libopenblas-dev \ | |
| libgfortran5 \ | |
| pkg-config \ | |
| doxygen \ | |
| graphviz \ | |
| gcovr | |
| - name: Install macOS system packages | |
| if: matrix.os-name == 'macOS' | |
| run: | | |
| brew update | |
| brew upgrade | |
| arch -arm64 brew install \ | |
| cmake \ | |
| ninja \ | |
| eigen \ | |
| boost \ | |
| hdf5 \ | |
| graphviz \ | |
| gcovr \ | |
| nlohmann-json \ | |
| bison \ | |
| flex \ | |
| googletest | |
| - name: Cache Doxygen (macOS) | |
| if: matrix.os-name == 'macOS' | |
| id: cache-doxygen | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ${{ github.workspace }}/doxygen_install | |
| key: doxygen-${{ runner.os }}-Release_1_9_8 | |
| - name: Build doxygen from source on macOS | |
| if: matrix.os-name == 'macOS' && steps.cache-doxygen.outputs.cache-hit != 'true' | |
| run: | | |
| # Clone repo for working Doxygen version | |
| git clone https://github.com/doxygen/doxygen.git | |
| cd doxygen | |
| # Checkout working release | |
| git checkout Release_1_9_8 | |
| mkdir build && cd build | |
| cmake -DBISON_EXECUTABLE=/opt/homebrew/Cellar/bison/3.8.2/bin/bison \ | |
| -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/doxygen_install" \ | |
| -DCMAKE_CXX_FLAGS="-Wno-missing-template-arg-list-after-template-kw $CMAKE_CXX_FLAGS" \ | |
| -G "Unix Makefiles" .. | |
| make -j$(sysctl -n hw.ncpu) | |
| make install | |
| - name: Add Doxygen to PATH (macOS) | |
| if: matrix.os-name == 'macOS' | |
| run: | | |
| echo "PATH=${{ github.workspace }}/doxygen_install/bin:$PATH" >> $GITHUB_ENV | |
| - name: Cache C++ dependency install # Checks if manifest files or build script have changed to rebuild dependencies | |
| id: cache-cpp-deps | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ${{ env.CPP_DEPS_PREFIX }} | |
| key: >- | |
| cpp-deps-${{ runner.os }}-${{ matrix.uarch }}- | |
| ${{ hashFiles('cpp/manifest/qdk-chemistry/cgmanifest.json', 'external/macis/manifest/cgmanifest.json', '.devcontainer/scripts/install_cpp_dependencies.sh') }} | |
| - name: Add C++ deps prefix to CMake search path | |
| run: | | |
| echo "CMAKE_PREFIX_PATH=${{ env.CPP_DEPS_PREFIX }}:${CMAKE_PREFIX_PATH}" >> $GITHUB_ENV | |
| echo "LD_LIBRARY_PATH=${{ env.CPP_DEPS_PREFIX }}/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV | |
| echo "PATH=${{ env.CPP_DEPS_PREFIX }}/bin:${PATH}" >> $GITHUB_ENV | |
| - name: Install C++ dependencies | |
| if: steps.cache-cpp-deps.outputs.cache-hit != 'true' # Run the dependency build if we don't find the right hash in the cache | |
| env: | |
| INSTALL_PREFIX: ${{ env.CPP_DEPS_PREFIX }} | |
| BUILD_DIR: ${{ github.workspace }}/cpp_deps_build | |
| KEEP_BUILD_DIR: 1 | |
| run: | | |
| bash ${{ github.workspace }}/.devcontainer/scripts/install_cpp_dependencies.sh \ | |
| ${{ github.workspace }}/cpp/manifest/qdk-chemistry/cgmanifest.json \ | |
| ${{ github.workspace }}/external/macis/manifest/cgmanifest.json | |
| - name: Configure C++ RelWithDebInfo/Coverage build | |
| run: | | |
| cmake -S cpp -B "$BUILD_DIR" \ | |
| -GNinja \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | |
| -DQDK_UARCH="$QDK_UARCH" \ | |
| -DQDK_CHEMISTRY_ENABLE_COVERAGE=ON \ | |
| -DBUILD_TESTING=ON | |
| - name: Build C++ RelWithDebInfo/Coverage library | |
| run: cmake --build "$BUILD_DIR" | |
| - name: Run C++ tests in RelWithDebInfo/Coverage mode with coverage | |
| env: | |
| OMP_NUM_THREADS: ${{ matrix.cpp-test-threads }} | |
| run: | | |
| mkdir -p test-results ${{ github.workspace }}/coverage-reports | |
| cd "$BUILD_DIR" | |
| echo "=== Running C++ Tests in Debug Mode with Coverage ===" | |
| set +e | |
| if [ "$QDK_UARCH" == "native" ]; then # Exclude particular test on macOS builds | |
| ctest --output-on-failure --verbose --timeout 300 --output-junit ${{ github.workspace }}/test-results/ctest_results.xml -E "MACIS_SERIAL_TEST|AtomInitGuessEnergyConvergence" | |
| else | |
| ctest --output-on-failure --verbose --timeout 300 --output-junit ${{ github.workspace }}/test-results/ctest_results.xml -E "MACIS_SERIAL_TEST" | |
| fi | |
| CTEST_EXIT_CODE=$? | |
| set -e | |
| if [ $CTEST_EXIT_CODE -ne 0 ]; then | |
| echo "=== Some tests failed ===" | |
| echo "Exit code: $CTEST_EXIT_CODE" | |
| fi | |
| cd ${{ github.workspace }} | |
| gcovr --root ${{ github.workspace }}/cpp \ | |
| --object-directory "${{ github.workspace }}/${BUILD_DIR}" \ | |
| --filter '${{ github.workspace }}/cpp/src/.*' \ | |
| --filter '${{ github.workspace }}/cpp/include/.*' \ | |
| --exclude '.*/tests/.*' \ | |
| --exclude '.*test.*\.cpp' \ | |
| --exclude '.*gtest.*' \ | |
| --exclude '.*gmock.*' \ | |
| --exclude '.*/external/.*' \ | |
| --html-details ${{ github.workspace }}/coverage-reports/cpp_coverage.html \ | |
| --xml ${{ github.workspace }}/coverage-reports/cpp_coverage.xml \ | |
| --txt ${{ github.workspace }}/coverage-reports/cpp_coverage.txt \ | |
| --merge-mode-functions=separate \ | |
| --gcov-ignore-parse-errors | |
| echo "C++ Coverage Summary:" | |
| cat ${{ github.workspace }}/coverage-reports/cpp_coverage.txt | |
| if [ $CTEST_EXIT_CODE -ne 0 ]; then | |
| exit $CTEST_EXIT_CODE | |
| fi | |
| - name: Install C++ library | |
| run: | | |
| cmake --install "$BUILD_DIR" | |
| - name: Test C++ installation | |
| run: | | |
| cmake -S examples/language/cpp -B build_example -GNinja -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install | |
| cmake --build build_example --target all | |
| echo "C++ Example Compiled with Pre-Installed QDK/Chemistry-C++ Libraries!" | |
| - name: Install Python package | |
| working-directory: python | |
| env: | |
| QDK_CHEMISTRY_ENABLE_COVERAGE: 1 | |
| CMAKE_BUILD_TYPE: RelWithDebInfo | |
| run: | | |
| # Remove CMake files to build Python package without picking the installed library | |
| rm -r ${{ github.workspace }}/install/lib/cmake/qdk | |
| # Use persistent build directory for coverage analysis | |
| # Note: qiskit-extras is not supported on Python 3.14 | |
| if [ "${{ matrix.skip-qiskit-extras }}" == "true" ]; then | |
| echo "Skipping qiskit-extras installation (not supported on Python ${{ matrix.python-version }})" | |
| python -m pip install --prefix=${{ github.workspace }}/install -C build-dir="build/{wheel_tag}" .[plugins,dev,docs,coverage] | |
| else | |
| python -m pip install --prefix=${{ github.workspace }}/install -C build-dir="build/{wheel_tag}" .[all] | |
| fi | |
| python3 -c "import qdk_chemistry; print('qdk_chemistry version:', qdk_chemistry.__version__)" | |
| # Install optional dependencies for tests | |
| python -m pip install --prefix=${{ github.workspace }}/install pennylane gast ipykernel | |
| # Register the Jupyter kernel for notebook tests | |
| python -m ipykernel install --user --name python3 --display-name "Python 3" | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install --prefix=${{ github.workspace }}/install coverage pytest pytest-cov | |
| - name: Run Python tests | |
| env: | |
| OMP_NUM_THREADS: ${{ matrix.python-test-threads }} | |
| QDK_CHEMISTRY_RUN_SLOW_TESTS: 0 | |
| working-directory: python | |
| run: | | |
| set -e | |
| mkdir -p ../test-results ../coverage-reports | |
| BUILD_TEMP=$(find . -type d -path './build/cp*' -print -quit) | |
| echo "Found build directory: $BUILD_TEMP" | |
| set +e | |
| set -o pipefail | |
| pytest \ | |
| --cov=qdk_chemistry \ | |
| --cov-report=xml:../coverage-reports/python_coverage.xml \ | |
| --cov-report=html:../coverage-reports/python_coverage_html \ | |
| --cov-report=term \ | |
| --junitxml=../test-results/pytest_report.xml \ | |
| -v \ | |
| --tb=short \ | |
| 2>&1 | tee ../coverage-reports/python_coverage.txt | |
| PYTEST_EXIT_CODE=${PIPESTATUS[0]} | |
| set -e | |
| echo "=== Python Test Output ===" | |
| cat ../coverage-reports/python_coverage.txt | |
| if [ $PYTEST_EXIT_CODE -ne 0 ]; then | |
| echo "ERROR: Python tests failed with exit code $PYTEST_EXIT_CODE" | |
| fi | |
| if [ -n "$BUILD_TEMP" ] && [ -d "$BUILD_TEMP" ]; then | |
| find "$BUILD_TEMP" -name "*.gcda" -exec cp {} coverage_build/ \; 2>/dev/null || true | |
| fi | |
| if [ $PYTEST_EXIT_CODE -ne 0 ]; then | |
| exit 1 | |
| fi | |
| - name: Generate Pybind11 coverage report | |
| working-directory: python | |
| run: | | |
| PYBIND_BUILD_DIR=$(find . -wholename "./build/cp*/CMakeFiles/_core.dir" | head -1) | |
| CLEAN_BUILD_DIR="${PYBIND_BUILD_DIR#./}" | |
| gcovr \ | |
| --root ${{ github.workspace }}/python \ | |
| --object-directory "${{ github.workspace }}/python/$CLEAN_BUILD_DIR" \ | |
| --filter '.*src/pybind11.*' \ | |
| --filter '.*src/cpp.*' \ | |
| --exclude '.*test.*' \ | |
| --exclude '.*external.*' \ | |
| --gcov-ignore-errors=no_working_dir_found \ | |
| --gcov-ignore-errors=source_not_found \ | |
| --xml "../coverage-reports/pybind11_coverage.xml" \ | |
| --txt "../coverage-reports/pybind11_coverage.txt" \ | |
| --html-details "../coverage-reports/pybind11_coverage.html" | |
| echo "Pybind11 Coverage Summary:" | |
| cat ../coverage-reports/pybind11_coverage.txt | |
| - name: Generate coverage statistics | |
| run: | | |
| # Extract coverage percentages | |
| CPP_COVERAGE=$(grep -oP 'TOTAL.*?\K[0-9.]+(?=%)' coverage-reports/cpp_coverage.txt | tail -1 || echo "0") | |
| PYTHON_COVERAGE=$(grep -oP 'TOTAL.*?\K[0-9]+(?=%)' coverage-reports/python_coverage.txt | tail -1 || echo "0") | |
| PYBIND11_COVERAGE=$(grep -oP 'TOTAL.*?\K[0-9.]+(?=%)' coverage-reports/pybind11_coverage.txt | tail -1 || echo "0") | |
| echo "CPP_COVERAGE=$CPP_COVERAGE" >> $GITHUB_ENV | |
| echo "PYTHON_COVERAGE=$PYTHON_COVERAGE" >> $GITHUB_ENV | |
| echo "PYBIND11_COVERAGE=$PYBIND11_COVERAGE" >> $GITHUB_ENV | |
| # Create simple PR comment with just statistics | |
| echo "## 📊 Coverage Summary" > pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo "| Component | Coverage |" >> pr-comment.md | |
| echo "|-----------|----------|" >> pr-comment.md | |
| echo "| C++ Library | ${CPP_COVERAGE}% |" >> pr-comment.md | |
| echo "| Python Package | ${PYTHON_COVERAGE}% |" >> pr-comment.md | |
| if [ "$PYBIND11_COVERAGE" != "0" ]; then | |
| echo "| Pybind11 Bindings | ${PYBIND11_COVERAGE}% |" >> pr-comment.md | |
| fi | |
| echo "" >> pr-comment.md | |
| echo "---" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo "### Detailed Coverage Reports" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo "<details>" >> pr-comment.md | |
| echo "<summary>C++ Coverage Details</summary>" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| cat coverage-reports/cpp_coverage.txt >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| echo "</details>" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| if [ -f coverage-reports/python_coverage.txt ]; then | |
| echo "<details>" >> pr-comment.md | |
| echo "<summary>Python Coverage Details</summary>" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| tail -50 coverage-reports/python_coverage.txt >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| echo "</details>" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| fi | |
| if [ -f coverage-reports/pybind11_coverage.txt ]; then | |
| echo "<details>" >> pr-comment.md | |
| echo "<summary>Pybind11 Coverage Details</summary>" >> pr-comment.md | |
| echo "" >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| cat coverage-reports/pybind11_coverage.txt >> pr-comment.md | |
| echo '```' >> pr-comment.md | |
| echo "</details>" >> pr-comment.md | |
| fi | |
| - name: Comment PR with coverage | |
| if: github.event_name == 'pull_request' | |
| uses: thollander/actions-comment-pull-request@v2 | |
| with: | |
| filePath: pr-comment.md | |
| comment_tag: coverage-report | |
| - name: Add coverage to job summary | |
| run: | | |
| # Create comprehensive summary with table and detailed reports | |
| echo "## 📊 Coverage Summary" > coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo "| Component | Coverage |" >> coverage-summary.md | |
| echo "|-----------|----------|" >> coverage-summary.md | |
| echo "| C++ Library | ${CPP_COVERAGE}% |" >> coverage-summary.md | |
| echo "| Python Package | ${PYTHON_COVERAGE}% |" >> coverage-summary.md | |
| if [ "$PYBIND11_COVERAGE" != "0" ]; then | |
| echo "| Pybind11 Bindings | ${PYBIND11_COVERAGE}% |" >> coverage-summary.md | |
| fi | |
| echo "" >> coverage-summary.md | |
| echo "---" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo "### Detailed Coverage Reports" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo "<details>" >> coverage-summary.md | |
| echo "<summary>C++ Coverage Details</summary>" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| cat coverage-reports/cpp_coverage.txt >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| echo "</details>" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| if [ -f coverage-reports/python_coverage.txt ]; then | |
| echo "<details>" >> coverage-summary.md | |
| echo "<summary>Python Coverage Details</summary>" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| tail -50 coverage-reports/python_coverage.txt >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| echo "</details>" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| fi | |
| if [ -f coverage-reports/pybind11_coverage.txt ]; then | |
| echo "<details>" >> coverage-summary.md | |
| echo "<summary>Pybind11 Coverage Details</summary>" >> coverage-summary.md | |
| echo "" >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| cat coverage-reports/pybind11_coverage.txt >> coverage-summary.md | |
| echo '```' >> coverage-summary.md | |
| echo "</details>" >> coverage-summary.md | |
| fi | |
| # Add to job summary | |
| cat coverage-summary.md >> $GITHUB_STEP_SUMMARY | |
| - name: Build documentation | |
| if: matrix.python-version == '3.13' | |
| working-directory: docs | |
| run: | | |
| set +e | |
| make clean all | |
| MAKE_EXIT_CODE=$? | |
| set -e | |
| if [ $MAKE_EXIT_CODE -ne 0 ]; then | |
| echo "=== Documentation build failed ===" | |
| echo "=== Contents of all .txt output files ===" | |
| for txtfile in *-output.txt *-warnings.txt; do | |
| if [ -f "$txtfile" ]; then | |
| echo "" | |
| echo "==== File: $txtfile ====" | |
| cat "$txtfile" | |
| fi | |
| done | |
| exit $MAKE_EXIT_CODE | |
| fi |