name: Ubuntu CI

on:
  push:
    paths-ignore:
      - ".devcontainer/**"
      - ".vscode/**"
      - "doc/**"
      - "*.md"
  pull_request:
    paths-ignore:
      - ".devcontainer/**"
      - ".vscode/**"
      - "doc/**"
      - "*.md"

jobs:
  gcc-build:
    name: GCC build
    strategy:
      matrix:
        python-version: ["3.11"]
    runs-on: "ubuntu-24.04"
    env:
      CXX_COMPILER: "/usr/lib/ccache/g++"
      C_COMPILER: "/usr/lib/ccache/gcc"
      QULACS_OPT_FLAGS: "-mtune=haswell -march=haswell -mfpmath=both"
      COVERAGE: "Yes"
      USE_TEST: "Yes"
    steps:
      - uses: actions/checkout@v4

      - name: Setup cmake
        uses: lukka/get-cmake@latest

      - name: Setup ccache
        uses: hendrikmuhs/ccache-action@v1.2
        with:
          key: "${{ github.job }}-ubuntu-24.04"
          verbose: 2

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install boost
        run: sudo apt install libboost-dev

      - name: Install LCOV
        run: |
          git clone -b v1.15 --depth 1 https://github.com/linux-test-project/lcov.git
          cd lcov
          sudo make install

      - name: Install qulacs for Ubuntu
        run: ./script/build_gcc.sh

      - name: Install qulacs Python module
        run: pip install .[ci]

      - name: Test in Ubuntu
        run: |
          cd ./build
          make coverage -j $(nproc)
          make pythontest -j $(nproc)

      - name: Upload coverage to codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  gcc-build-with-address-sanitizer:
    name: GCC build with -fsanitizer=address enabled
    runs-on: "ubuntu-24.04"
    env:
      CXX_COMPILER: "/usr/lib/ccache/g++"
      C_COMPILER: "/usr/lib/ccache/gcc"
      QULACS_OPT_FLAGS: "-mtune=haswell -march=haswell -mfpmath=both"
      USE_TEST: "Yes"
    steps:
      - uses: actions/checkout@v4

      - name: Setup cmake
        uses: lukka/get-cmake@latest

      - name: Setup ccache
        uses: hendrikmuhs/ccache-action@v1.2
        with:
          key: "${{ github.job }}-ubuntu-24.04"
          verbose: 2

      - name: Install boost
        run: sudo apt install libboost-dev

      - name: Install qulacs for Ubuntu
        run: ./script/build_gcc_with_memory_sanitizer.sh

      - name: Test in Ubuntu
        # -j option is not appended because running this test in parallel is slower than sequential version.
        run: |
          cd ./build
          make test

  nvcc-gcc-GPUbuild:
    name: nvcc + gcc build
    runs-on: "ubuntu-24.04"
    env:
      CXX_COMPILER: "/usr/lib/ccache/g++"
      C_COMPILER: "/usr/lib/ccache/gcc"
      QULACS_OPT_FLAGS: "-mtune=haswell -march=haswell -mfpmath=both"
      PYTHON: "3.12.10"
      COVERAGE: "ON"
      USE_TEST: "Yes"
      USE_GPU: "Yes"
    steps:
      - uses: actions/checkout@v4

      - name: Setup cmake
        uses: lukka/get-cmake@latest

      - name: Setup ccache
        uses: hendrikmuhs/ccache-action@v1.2
        with:
          key: "${{ github.job }}-ubuntu-24.04"
          verbose: 2

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12.10"
          architecture: x64

      - name: Install boost
        run: sudo apt install libboost-dev

      - name: Install CUDA toolkit
        uses: Jimver/cuda-toolkit@v0.2.23
        with:
          cuda: "12.6.3"
          method: "network"

      - name: Install qulacs for Ubuntu
        run: ./script/build_gcc_with_gpu.sh

      - name: Install qulacs Python module
        run: pip install .[test]

      - name: Build test
        run: make -C build buildtest -j $(nproc)

      # Testing is removed because GPU is not available for GitHub-Hosted Runner.

  gcc11-sve-build:
    name: GCC11 + armv8.2-a+sve build
    runs-on: "ubuntu-24.04"
    env:
      C_COMPILER: "aarch64-linux-gnu-gcc-11"
      CXX_COMPILER: "aarch64-linux-gnu-g++-11"
      QULACS_OPT_FLAGS: "-march=armv8.2-a+sve"
      QEMU_LD_PREFIX: "/usr/aarch64-linux-gnu"
    steps:
      - uses: actions/checkout@v4

      - name: Setup qemu
        run: |
          sudo apt-get update
          sudo apt-get install -y cmake ninja-build pkg-config libglib2.0-dev gcc-11-aarch64-linux-gnu g++-11-aarch64-linux-gnu
          wget -q https://download.qemu.org/qemu-7.2.17.tar.xz
          tar xJf qemu-7.2.17.tar.xz
          pushd qemu-7.2.17
          mkdir build; cd build
          ../configure --target-list=aarch64-linux-user
          make -s -j $(nproc)
          sudo make install

      - name: Install boost
        run: sudo apt-get install libboost-dev

      - name: Install qulacs for Ubuntu
        run: USE_TEST=Yes ./script/build_gcc.sh

      - name: Test in Ubuntu
        run: |
          cd ./build
          make buildtest -j $(nproc)
          file ../bin/csim_test
          QEMU_CPU="max,sve512=on" qemu-aarch64 ../bin/csim_test
          QEMU_CPU="max,sve256=on" qemu-aarch64 ../bin/csim_test
          file ../bin/cppsim_test
          QEMU_CPU="max,sve512=on" qemu-aarch64 ../bin/cppsim_test
          QEMU_CPU="max,sve256=on" qemu-aarch64 ../bin/cppsim_test
          file ../bin/vqcsim_test
          QEMU_CPU="max,sve512=on" qemu-aarch64 ../bin/vqcsim_test
          QEMU_CPU="max,sve256=on" qemu-aarch64 ../bin/vqcsim_test

  format:
    name: Format with clang-format
    runs-on: "ubuntu-24.04"
    steps:
      - uses: actions/checkout@v4

      - run: |
          sudo apt-get install clang-format-14
          sudo ln -s /usr/bin/clang-format-14 /usr/local/bin/clang-format
          which clang-format
          clang-format --version

      - name: format
        run: |
          ./script/format.sh

      - name: Compare diff
        run: |
          diff=$(git diff)
          echo -n "$diff"
          # Without `-n`, `echo -n "$diff" | wc -l` is 1 even if `"$diff" is empty.`
          test $(echo -n "$diff" | wc -l) -eq 0

  python-format:
    name: Format with Python formatters
    runs-on: "ubuntu-24.04"
    strategy:
      matrix:
        python-version: ["3.11"]

    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          architecture: x64

      - name: Install formatters
        run: python -m pip install black isort

      - name: Check format
        run: |
          python -m black . --check --diff
          python -m isort . --check --diff

  mpicc-build:
    name: MPICC build
    strategy:
      matrix:
        python-version: ["3.11"]
    runs-on: "ubuntu-24.04"
    env:
      CXX_COMPILER: "mpic++"
      C_COMPILER: "mpicc"
      QULACS_OPT_FLAGS: "-mtune=haswell -march=haswell -mfpmath=both"
      PYTHON: ${{ matrix.python-version }}
      COVERAGE: "ON"
    steps:
      - uses: actions/checkout@v4

      - name: Setup cmake
        uses: lukka/get-cmake@latest

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          architecture: x64

      - name: Install mpi-bin and libmpi
        run: sudo apt install openmpi-bin libopenmpi-dev

      - name: Install boost
        run: sudo apt install libboost-dev

      - name: Install LCOV
        run: |
          git clone -b v1.15 --depth 1 https://github.com/linux-test-project/lcov.git
          cd lcov
          sudo make install

      - name: Install qulacs for Ubuntu
        run: USE_TEST=Yes ./script/build_mpicc.sh

      - name: Install qulacs Python module
        run: USE_MPI=Yes pip install .[ci]

      - name: Install MPI Python module
        run: pip install mpi4py

      - name: Test in Ubuntu
        run: |
          cd ./build
          make coverage
          make pythontest

      - name: Test in Ubuntu
        run: |
          pip install pytest
          mpirun -n 2 bin/cppsim_test --gtest_filter="*multicpu*"
          mpirun -n 2 bin/vqcsim_test --gtest_filter="*multicpu*"
          mpirun -n 2 pytest python/tests/multi_cpu

      - name: Upload coverage to codecov
        uses: codecov/codecov-action@v4
