diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8ac259592..8834b67dbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: shell: bash - name: Run qobj run: | - pip install -U qiskit-terra + pip install -U qiskit python tools/generate_qobj.py cd out Release/qasm_simulator ../qobj.json | python ../tools/verify_standalone_results.py @@ -109,7 +109,7 @@ jobs: shell: bash - name: Run qobj run: | - pip install -U qiskit-terra + pip install -U qiskit python tools/generate_qobj.py cd out /usr/bin/mpirun.openmpi -host localhost:2 -np 2 Release/qasm_simulator ../qobj.json | python ../tools/verify_standalone_results.py diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fc5b9877d2..72e0be04de 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,39 +10,37 @@ jobs: matrix: os: ["macOS-latest", "ubuntu-latest", "windows-2019"] runs-on: ${{ matrix.os }} + environment: release steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.11.2 + python -m pip install cibuildwheel==2.16.2 - name: Build wheels env: AER_CMAKE_OPENMP_BUILD: 1 run: python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Publish Wheels - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit - run : | - pip install -U twine - twine upload wheelhouse/* + name: publish-shared-wheels build_wheels_aarch64: name: Build wheels on ${{ matrix.os }} runs-on: ${{ matrix.os }} + environment: release + permissions: + id-token: write strategy: fail-fast: false matrix: os: [ubuntu-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' @@ -55,73 +53,78 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.11.2 twine + python -m pip install cibuildwheel==2.16.2 - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: CIBW_BEFORE_ALL_LINUX: "yum install -y https://dl.fedoraproject.org/pub/epel/7/aarch64/Packages/e/epel-release-7-12.noarch.rpm && yum install -y openblas-devel" CIBW_ARCHS_LINUX: aarch64 - - uses: actions/upload-artifact@v2 + CIBW_TEST_SKIP: "cp38* cp39* cp310* cp311*" + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Upload to PyPI - run: twine upload ./wheelhouse/*.whl - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: wheelhouse wheel-arm64-macos: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: ["macOS-latest"] + environment: release steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python Python 3.8 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install deps - run: python -m pip install -U cibuildwheel==2.11.2 twine + run: python -m pip install -U cibuildwheel==2.16.2 - name: Build Wheels env: CIBW_ARCHS_MACOS: arm64 run: cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Upload to PyPI - run: twine upload ./wheelhouse/*.whl - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit + name: publish-shared-wheels sdist: name: Publish qiskit-aer sdist runs-on: ubuntu-latest + environment: release + permissions: + id-token: write steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' - name: Install Deps - run: pip install -U twine wheel + run: pip install -U scikit-build wheel - name: Build Artifacts run: | python setup.py sdist shell: bash - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./dist/qiskit* - - name: Publish to PyPi - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit - run: twine upload dist/qiskit* + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist gpu-build-cuda11: name: Build qiskit-aer-gpu-cu11 wheels - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} + environment: release + permissions: + id-token: write steps: - name: Maximize build space uses: easimon/maximize-build-space@master @@ -133,36 +136,39 @@ jobs: remove-haskell: 'true' remove-codeql: 'true' remove-docker-images: 'true' - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.11.2 + python -m pip install cibuildwheel==2.16.2 - name: Build wheels env: CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-rhel7-11-8-local-11.8.0_520.61.05-1.x86_64.rpm && rpm -i cuda-repo-rhel7-11-8-local-11.8.0_520.61.05-1.x86_64.rpm && yum clean all && yum -y install cuda && yum -y install openblas-devel && yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo && yum clean all" CIBW_BEFORE_BUILD : "pip install nvidia-cuda-runtime-cu11 nvidia-cublas-cu11 nvidia-cusolver-cu11 nvidia-cusparse-cu11 cuquantum-cu11" - CIBW_SKIP: "*-manylinux_i686 pp* cp36* *musllinux*" + CIBW_SKIP: "*-manylinux_i686 pp* cp36* cp37* cp312* *musllinux*" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu-cu11 QISKIT_AER_CUDA_MAJOR=11 CMAKE_VERBOSE_MAKEFILE=true AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc AER_CUDA_ARCH="7.0 7.2 7.5 8.0 8.6 8.7" AER_PYTHON_CUDA_ROOT=/opt/_internal AER_CIBUILD=true CIBW_REPAIR_WHEEL_COMMAND: 'auditwheel repair --exclude libcudart.so.11.0 --exclude libcustatevec.so.1 --exclude libcutensornet.so.2 --exclude libcutensor.so.1 --exclude libcutensorMg.so.1 --exclude libcusolver.so.11 --exclude libcusolverMg.so.11 --exclude libcusparse.so.11 --exclude libcublas.so.11 --exclude libcublasLt.so.11 -w {dest_dir} {wheel}' run: | python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Publish Wheels - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit - run : | - pip install -U twine - twine upload wheelhouse/* + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: wheelhouse gpu-build-cuda12: name: Build qiskit-aer-gpu-cu12 wheels - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} + environment: release + permissions: + id-token: write steps: - name: Maximize build space uses: easimon/maximize-build-space@master @@ -174,43 +180,43 @@ jobs: remove-haskell: 'true' remove-codeql: 'true' remove-docker-images: 'true' - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.11.2 + python -m pip install cibuildwheel==2.16.2 - name: Build wheels env: - CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/12.1.1/local_installers/cuda-repo-rhel7-12-1-local-12.1.1_530.30.02-1.x86_64.rpm && rpm -i cuda-repo-rhel7-12-1-local-12.1.1_530.30.02-1.x86_64.rpm && yum clean all && yum -y install cuda && yum -y install openblas-devel && yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo && yum clean all" - CIBW_BEFORE_BUILD : "pip install nvidia-cuda-runtime-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 cuquantum-cu12" - CIBW_SKIP: "*-manylinux_i686 pp* cp36* *musllinux*" + CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/12.2.2/local_installers/cuda-repo-rhel7-12-2-local-12.2.2_535.104.05-1.x86_64.rpm && rpm -i cuda-repo-rhel7-12-2-local-12.2.2_535.104.05-1.x86_64.rpm && yum clean all && yum -y install nvidia-driver-latest-dkms && yum -y install cuda && yum -y install openblas-devel && yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo && yum clean all" + CIBW_BEFORE_BUILD : "pip install nvidia-cuda-runtime-cu12 nvidia-nvjitlink-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 cuquantum-cu12" + CIBW_SKIP: "*-manylinux_i686 pp* cp36* cp37* cp312* *musllinux*" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu QISKIT_AER_CUDA_MAJOR=12 CMAKE_VERBOSE_MAKEFILE=true AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc AER_CUDA_ARCH="7.0 7.2 7.5 8.0 8.6 8.7 9.0" AER_PYTHON_CUDA_ROOT=/opt/_internal AER_CIBUILD=true CIBW_REPAIR_WHEEL_COMMAND: 'auditwheel repair --exclude libcudart.so.12 --exclude libcustatevec.so.1 --exclude libcutensornet.so.2 --exclude libcutensor.so.1 --exclude libcutensorMg.so.1 --exclude libcusolver.so.11 --exclude libcusolverMg.so.11 --exclude libcusolver.so.12 --exclude libcusolverMg.so.12 --exclude libcusparse.so.12 --exclude libcublas.so.12 --exclude libcublasLt.so.12 --exclude libnvJitLink.so.12 -w {dest_dir} {wheel}' run: | python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Publish Wheels - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit - run : | - pip install -U twine - twine upload wheelhouse/* + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: wheelhouse build_wheels_s390x: name: Build wheels on s390x runs-on: ${{ matrix.os }} + environment: release + permissions: + id-token: write strategy: fail-fast: false matrix: os: [ubuntu-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' @@ -222,31 +228,31 @@ jobs: with: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v2.11.2 + uses: pypa/cibuildwheel@v2.16.2 env: CIBW_ARCHS_LINUX: s390x CIBW_TEST_SKIP: "cp*" CIBW_BEFORE_ALL: "yum install -y epel-release && yum install -y openblas-devel" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Install twine - run: python -m pip install twine - - name: Upload to PyPI - run: twine upload ./wheelhouse/*.whl - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: wheelhouse build_wheels_ppc64le: name: Build wheels on ppc64le runs-on: ${{ matrix.os }} + environment: release + permissions: + id-token: write strategy: fail-fast: false matrix: os: [ubuntu-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 name: Install Python with: python-version: '3.8' @@ -258,18 +264,31 @@ jobs: with: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v2.11.2 + uses: pypa/cibuildwheel@v2.16.2 env: CIBW_ARCHS_LINUX: ppc64le CIBW_TEST_SKIP: "cp*" CIBW_BEFORE_ALL: "yum install -y epel-release && yum install -y openblas-devel" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl - - name: Install twine - run: python -m pip install twine - - name: Upload to PyPI - run: twine upload ./wheelhouse/*.whl - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: qiskit + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: wheelhouse + publish-shared-wheels: + name: Publish shared wheels + runs-on: ubuntu-latest + needs: [wheel-build, wheel-arm64-macos] + environment: release + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v3 + with: + path: deploy + name: publish-shared-wheels + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: deploy diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index 6c5ffaae34..eb922217d0 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -21,10 +21,13 @@ jobs: python -m pip install --upgrade pip pip install -U virtualenv setuptools wheel tox sudo apt-get install graphviz pandoc build-essential libopenblas-dev - - name: Build and publish + - name: Build docs env: - encrypted_rclone_key: ${{ secrets.encrypted_rclone_key }} - encrypted_rclone_iv: ${{ secrets.encrypted_rclone_iv }} QISKIT_DOCS_BUILD_TUTORIALS: 'always' - run: | - tools/deploy_documentation.sh + run: tox -edocs + - name: Bypass Jekyll Processing # Necessary for setting the correct css path + run: touch docs/_build/html/.nojekyll + - name: Deploy + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: docs/_build/html/ diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 28b533ac6c..192e7bcd07 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -72,7 +72,7 @@ jobs: git clone https://github.com/Qiskit/qiskit-tutorials --depth=1 python -m pip install --upgrade pip wheel pip install -U -r requirements-dev.txt -c constraints.txt - pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + pip install -c constraints.txt git+https://github.com/Qiskit/qiskit pip install -c constraints.txt . pip install -U "qiskit-ibmq-provider" "z3-solver" "qiskit-ignis" "qiskit-aqua" "pyscf<1.7.4" "matplotlib>=3.3.0" jupyter pylatexenc nbsphinx cvxpy qiskit-sphinx-theme -c constraints.txt sudo apt install -y graphviz pandoc libopenblas-dev diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 471ecfe0ee..88a9b13feb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -32,7 +32,7 @@ jobs: run: | set -e pip install -U pip wheel - pip install -U -c constraints.txt -r requirements-dev.txt qiskit-terra numpy scipy + pip install -U -c constraints.txt -r requirements-dev.txt qiskit numpy scipy shell: bash - name: Run clang-format run: | @@ -175,8 +175,8 @@ jobs: - name: Install Aer run: | set -e - python -I -m build --wheel --config-setting=--build-option=-- --config-setting=--build-option=-DTEST_JSON=1 - pip install --find-links=dist qiskit-aer + python -I -m build --wheel --config-setting=--build-option=-DTEST_JSON=1 + pip install -U dist/*.whl - name: Run Tests run: | set -e @@ -267,7 +267,7 @@ jobs: run: | set -e python -I -m build --wheel - pip install --find-links=dist qiskit-aer + pip install -U dist/*.whl shell: bash - name: Run Tests env: @@ -280,3 +280,4 @@ jobs: rm -rf qiskit_aer stestr run --slowest shell: bash + \ No newline at end of file diff --git a/.github/workflows/unit-tests-latest-qiskit.yml b/.github/workflows/unit-tests-latest-qiskit.yml new file mode 100644 index 0000000000..425538529c --- /dev/null +++ b/.github/workflows/unit-tests-latest-qiskit.yml @@ -0,0 +1,54 @@ +name: Unit Tests for latest Qiskit +on: + schedule: + - cron: '0 5 * * *' +concurrency: + group: ${{ github.repository }}-${{ github.ref }}-${{ github.head_ref }}-${{ github.workflow }} + cancel-in-progress: true +jobs: + unit-tests-latest-qiskit: + runs-on: ubuntu-latest + timeout-minutes: 60 + env: + AER_THRUST_BACKEND: OMP + QISKIT_TEST_CAPTURE_STREAMS: 1 + # Needed to suppress a warning in jupyter-core 5.x by eagerly migrating to + # a new internal interface that will be the default in jupyter-core 6.x. + # This variable should become redundant on release of jupyter-core 6. + JUPYTER_PLATFORM_DIRS: 1 + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: 3.11 + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: | + python -m pip install -U -c constraints.txt -r requirements-dev.txt wheel + pip install -U git+https://github.com/Qiskit/qiskit.git + - name: Install openblas + run: | + set -e + sudo apt-get update + sudo apt-get install -y libopenblas-dev + shell: bash + - name: Install Aer + run: | + python -m pip install -U . + - name: Run Tests + run: | + set -e + pip check + rm -rf qiskit_aer + stestr run --slowest + shell: bash + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 517ce982e7..3d158eb7b7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,8 @@ endif() option(STATIC_LINKING "Specify if we want statically link the executable (for redistribution mainly)" FALSE) option(BUILD_TESTS "Specify whether we want to build tests or not" FALSE) +option(USE_BUNDLED_BLAS_WIN "Use the bundled openblas library on Windows when + not using AER_BLAS_LIB_PATH" TRUE) # Allow disabling conan for downstream package managers. Requires all libraries to be present in path # Default is value of environment variable if defined or ON @@ -237,7 +239,7 @@ else() set(BLA_VENDOR "OpenBLAS") endif() endif() - if(WIN32) + if(WIN32 AND USE_BUNDLED_BLAS_WIN) message(STATUS "Uncompressing OpenBLAS static library...") set(WIN_ARCH "win64" ) if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") # Checking if win32 build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 152affcccc..4f39f0b9b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ included in the Qiskit documentation: https://qiskit.org/documentation/contributing_to_qiskit.html -## Contributing to Qiskit Aer +## Contributing to Aer In addition to the general guidelines, there are specific details for contributing to Aer. These are documented below. @@ -105,33 +105,33 @@ look something like:: ```yaml features: - | - Introduced a new feature foo, that adds support for doing something to - ``QuantumCircuit`` objects. It can be used by using the foo function, + Introduced a new feature ``foo``, that adds support for doing something to + ``AerProvider`` objects. It can be used by using the ``foo`` function, for example:: - from qiskit import foo - from qiskit import QuantumCircuit - foo(QuantumCircuit()) + from qiskit_aer import foo + from qiskit_aer import AerProvider + foo(AerProvider()) - | - The ``qiskit.QuantumCircuit`` module has a new method ``foo()``. This is - the equivalent of calling the ``qiskit.foo()`` to do something to your - QuantumCircuit. This is the equivalent of running ``qiskit.foo()`` on - your circuit, but provides the convenience of running it natively on + The ``qiskit_aer.AerProvider`` module has a new method ``foo()``. This is + the equivalent of calling the ``qiskit_aer.foo()`` to do something to your + ``AerProvider``. This is the equivalent of running ``qiskit_aer.foo()`` on + your provider, but it has the convenience of running it natively on an object. For example:: - from qiskit import QuantumCircuit + from qiskit_aer import AerProvider - circ = QuantumCircuit() - circ.foo() + provider = AerProvider() + provider.foo() deprecations: - | - The ``qiskit.bar`` module has been deprecated and will be removed in a + The ``qiskit_aer.bar`` module has been deprecated and will be removed in a future release. Its sole function, ``foobar()`` has been superseded by the - ``qiskit.foo()`` function which provides similar functionality but with + ``qiskit_aer.foo()`` function which provides similar functionality but with more accurate results and better performance. You should update your calls - ``qiskit.bar.foobar()`` calls to ``qiskit.foo()``. + ``qiskit_aer.bar.foobar()`` calls to ``qiskit_aer.foo()``. ``` You can also look at other release notes for other examples. @@ -180,7 +180,7 @@ it has been tagged:: At release time, ``reno report`` is used to generate the release notes for the release and the output will be submitted as a pull request to the documentation repository's [release notes file]( -https://github.com/Qiskit/qiskit/blob/master/docs/release_notes.rst) +https://github.com/Qiskit/qiskit-aer/blob/master/docs/release_notes.rst) #### Building release notes locally @@ -193,7 +193,7 @@ particular will be located at `docs/_build/html/release_notes.html` ## Style and lint -Qiskit Aer uses 3 tools for verifying code formatting and lint checking. The +Aer uses 3 tools for verifying code formatting and lint checking. The first tool is [black](https://github.com/psf/black) which is a Python code formatting tool that will automatically update the code formatting to a consistent style. The second tool is [pylint](https://www.pylint.org/) which is a code linter @@ -211,7 +211,7 @@ any error you will have to fix these issues by manually updating your code. ### Development Cycle -The development cycle for qiskit-aer is all handled in the open using +The development cycle for Aer is all handled in the open using the project boards in GitHub for project management. We use milestones in GitHub to track work for specific releases. The features or other changes that we want to include in a release will be tagged and discussed in GitHub. @@ -222,12 +222,12 @@ previous version in the release notes. * `main`: -The main branch is used for development of the next version of qiskit-aer. +The main branch is used for development of the next version of Aer. It will be updated frequently and should not be considered stable. The API can and will change on main as we introduce and refine new features. * `stable/*` branches: -Branches under `stable/*` are used to maintain released versions of qiskit-aer. +Branches under `stable/*` are used to maintain released versions of `qiskit-aer`. It contains the version of the code corresponding to the latest release for that minor version on pypi. For example, stable/0.4 contains the code for the 0.4.0 release on pypi. The API on these branches are stable and the only changes @@ -235,7 +235,7 @@ merged to it are bugfixes. ### Release cycle -When it is time to release a new minor version of qiskit-aer, we will: +When it is time to release a new minor version of `qiskit-aer`, we will: 1. Create a new tag with the version number and push it to github 2. Change the `main` version to the next release version. @@ -268,7 +268,7 @@ window $ conda activate QiskitDevEnv ``` -- Clone the `Qiskit Aer` repo via *git*. +- Clone the `Aer` repo via *git*. ``` $ git clone https://github.com/Qiskit/qiskit-aer ``` @@ -301,7 +301,7 @@ You're now ready to build from source! Follow the instructions for your platform ### Linux -Qiskit is officially supported on Red Hat, CentOS, Fedora, and Ubuntu distributions, as long as you can install a GCC version that is C++14 compatible and a few dependencies we need. +Aer is officially supported on Red Hat, CentOS, Fedora, and Ubuntu distributions, as long as you can install a GCC version that is C++14 compatible and a few dependencies we need. #### Dependencies @@ -635,7 +635,7 @@ options we have on `Aer` to CMake, we use its native mechanism: ### Building with GPU support -Qiskit Aer can exploit GPU's horsepower to accelerate some simulations, specially the larger ones. +Aer can exploit GPU's horsepower to accelerate some simulations, specially the larger ones. GPU access is supported either via CUDA® (NVIDIA® chipset) or ROCm® (AMD® GPUs). #### Building with CUDA® support @@ -672,12 +672,12 @@ Few notes on CUDA® GPU builds: 3. We don't need NVIDIA® drivers for building, but we need them for running simulations 4. Only Linux platforms are supported -Qiskit Aer now supports cuQuantum optimized Quantum computing APIs from NVIDIA®. +Aer now supports cuQuantum optimized Quantum computing APIs from NVIDIA®. cuStateVec APIs can be exploited to accelerate statevector, density_matrix and unitary methods. cuTensorNet APIs can be exploited to tensor_network merthod. This implementation requires CUDA® toolkit version 11.2 or higher and Volta or Ampare architecture GPUs. -Before building Qiskit Aer with cuQuantum support, install required components via pip install as following. +Before building Aer with cuQuantum support, install required components via pip install as following. qiskit-aer$ pip install nvidia-cuda-runtime-cu11 nvidia-cublas-cu11 nvidia-cusolver-cu11 nvidia-cusparse-cu11 cuquantum-cu11 @@ -710,15 +710,15 @@ results = execute(circuit,sim,cuStateVec_enable=True).result() ``` #### Building with ROCm® support ROCm® support has been added matching the CUDA® implementation based -on the `thrust` library. This enables Qiskit-Aer to run on AMD® GPUs, +on the `thrust` library. This enables Aer to run on AMD® GPUs, including the AMD® Instinct GPU line based on the CDNA architecture. ROCm® only support linux platforms. To build the standalone version, the following should be sufficient: ``` -cmake -G Ninja \ - -DCMAKE_INSTALL_PREFIX= \ +cmake -G Ninja \ + -DCMAKE_INSTALL_PREFIX= \ -DSKBUILD=FALSE \ -DAER_THRUST_BACKEND=ROCM \ -DAER_MPI= \ @@ -730,7 +730,7 @@ ninja install Alternatively, and possibly preferred for most use cases, you can create a Python wheel file that you can install as part of your Python environemnt: ``` -cd +cd QISKIT_AER_PACKAGE_NAME='qiskit-aer-gpu-rocm' \ python3 setup.py bdist_wheel -- \ @@ -745,9 +745,9 @@ In both cases, the host system needs to have a functional ROCm® instalation and the environment variable `ROCM_PATH` set pointing to the ROCm® instalation folder if that is not the default `/opt/rocm`. Depending on how your Python environment is set, you might need to install -Qiskit-Aer's required development modules: +Aer's required development modules: ``` -cd +cd pip install -r requirements-dev.txt ``` @@ -763,11 +763,11 @@ results = execute(circuit,sim,cuStateVec_enable=True).result() ### Building with MPI support -Qiskit Aer can parallelize its simulation on the cluster systems by using MPI. +Aer can parallelize its simulation on the cluster systems by using MPI. This can extend available memory space to simulate quantum circuits with larger number of qubits and also can accelerate the simulation by parallel computing. To use MPI support, any MPI library (i.e. OpenMPI) should be installed and configured on the system. -Qiskit Aer supports MPI both with and without GPU support. Currently following simulation methods are supported to be parallelized by MPI. +Aer supports MPI both with and without GPU support. Currently following simulation methods are supported to be parallelized by MPI. - statevector - density_matrix @@ -795,7 +795,7 @@ For example, ### Running with multiple-GPUs and/or multiple nodes -Qiskit Aer parallelizes simulations by distributing quantum states into distributed memory space. +Aer parallelizes simulations by distributing quantum states into distributed memory space. To decrease data transfer between spaces the distributed states are managed as chunks that is a sub-state for smaller qubits than the input circuits. For example, @@ -809,7 +809,7 @@ And the (noiseless) swap gates are inserted to exchange data. Please refer to this paper (https://arxiv.org/abs/2102.02957) for more detailed algorithm and implementation of parallel simulation. So to simulate by using multiple GPUs or multiple nodes on the cluster, following configurations should be set to backend options. -(If there is not enough memory to simulate the input circuit, Qiskit Aer automatically set following options, but it is recommended to explicitly set them) +(If there is not enough memory to simulate the input circuit, Aer automatically set following options, but it is recommended to explicitly set them) - blocking_enable @@ -828,13 +828,13 @@ circ.measure_all() result = execute(circ, sim, shots=100, blocking_enable=True, blocking_qubits=23).result() ``` -To run Qiskit Aer with Python script with MPI parallelization, MPI executer such as mpirun should be used to submit a job on the cluster. Following example shows how to run Python script using 4 processes by using mpirun. +To run Aer with Python script with MPI parallelization, MPI executer such as mpirun should be used to submit a job on the cluster. Following example shows how to run Python script using 4 processes by using mpirun. ``` mpirun -np 4 python example.py ``` -MPI_Init function is called inside Qiskit Aer, so you do not have to manage MPI processes in Python script. +MPI_Init function is called inside Aer, so you do not have to manage MPI processes in Python script. Following metadatas are useful to find on which process is this script running. - num_mpi_processes : shows number of processes using for this simulation @@ -855,9 +855,9 @@ myrank = meta['mpi_rank'] Multiple shots are also distributed to multiple nodes when setting `device=GPU` and `batched_shots_gpu=True`. The results are distributed to each processes. -Note : In the script, make sure that the same random seed should be used for all processes so that the consistent circuits and parameters are passed to Qiskit Aer. To do so add following option to the script. +Note : In the script, make sure that the same random seed should be used for all processes so that the consistent circuits and parameters are passed to Aer. To do so add following option to the script. ``` -from qiskit.utils import algorithm_globals +from qiskit_algorithms.utils import algorithm_globals algorithm_globals.random_seed = consistent_seed_to_all_processes ``` @@ -966,6 +966,16 @@ These are the flags: Default: No value. Example: ``python ./setup.py bdist_wheel -- -DAER_BLAS_LIB_PATH=/path/to/look/for/blas/`` +* USE_BUNDLED_BLAS_WIN + + Tells CMake to use the bundled OpenBLAS library vendored into the source code when building on Windows. + When this option is set to `False`, CMake will use its standard method to search for the BLAS library aginst which to link instead of using the vendored version. + The `AER_BLAS_LIB_PATH` option takes precedence over this option. + + Values: True|False + Default: True + Example: ``python ./setup.py bdist_wheel -- -DUSE_BUNDLED_BLAS_WIN=FALSE`` + * BUILD_TESTS It will tell the build system to build C++ tests along with the simulator. @@ -1049,10 +1059,10 @@ These are the flags: Code contributions are expected to include tests that provide coverage for the changes being made. -We have two types of tests in the codebase: Qiskit Terra integration tests and +We have two types of tests in the codebase: Qiskit integration tests and Standalone integration tests. -For Qiskit Terra integration tests, you first need to build and install the Qiskit Python extension, and then run `unittest` Python framework. +For Qiskit integration tests, you first need to build and install the Qiskit Python extension, and then run ``unittest`` Python framework. ``` qiskit-aer$ pip install . @@ -1167,7 +1177,7 @@ After this, you can step through the code and continue with your debug session a ## Dealing with the git blame ignore list -In the qiskit-aer repository we maintain a list of commits for git blame to +In the ``Qiskit/qiskit-aer`` repository we maintain a list of commits for git blame to ignore. This is mostly commits that are code style changes that don't change the functionality but just change the code formatting (for example, when we migrated to use black for code formatting). This file, `.git-blame-ignore-revs` diff --git a/README.md b/README.md index a9c4795953..40492f4f3c 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Qiskit Aer +# Aer - high performance quantum circuit simulation for Qiskit [![License](https://img.shields.io/github/license/Qiskit/qiskit-aer.svg?style=popout-square)](https://opensource.org/licenses/Apache-2.0) [![Build](https://github.com/Qiskit/qiskit-aer/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/Qiskit/qiskit-aer/actions/workflows/build.yml) @@ -6,16 +6,14 @@ [![](https://img.shields.io/github/release/Qiskit/qiskit-aer.svg?style=popout-square)](https://github.com/Qiskit/qiskit-aer/releases) [![](https://img.shields.io/pypi/dm/qiskit-aer.svg?style=popout-square)](https://pypi.org/project/qiskit-aer/) -**Qiskit** is an open-source framework for working with noisy quantum computers at the level of pulses, circuits, and algorithms. - -Qiskit is made up of elements that work together to enable quantum computing. This element is **Aer**, which provides high-performance quantum computing simulators with realistic noise models. +**Aer** is a high performance simulator for quantum circuits written in Qiskit, that includes realistic noise models. ## Installation -We encourage installing Qiskit via the pip tool (a python package manager). The following command installs the core Qiskit components, including Aer. +We encourage installing Aer via the pip tool (a python package manager): ```bash -pip install qiskit qiskit-aer +pip install qiskit-aer ``` Pip will handle all dependencies automatically for us, and you will always install the latest (and well-tested) version. @@ -47,8 +45,8 @@ that have CUDA support, you will have to build from source. You can refer to the [contributing guide](CONTRIBUTING.md#building-with-gpu-support) for instructions on doing this. -## Simulating your first quantum program with Qiskit Aer -Now that you have Qiskit Aer installed, you can start simulating quantum circuits with noise. Here is a basic example: +## Simulating your first Qiskit circuit with Aer +Now that you have Aer installed, you can start simulating quantum circuits with noise. Here is a basic example: ``` $ python @@ -91,20 +89,19 @@ print('Counts(noise):', counts_noise) ## Contribution Guidelines -If you'd like to contribute to Qiskit, please take a look at our +If you'd like to contribute to Aer, please take a look at our [contribution guidelines](CONTRIBUTING.md). This project adheres to Qiskit's [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. We use [GitHub issues](https://github.com/Qiskit/qiskit-aer/issues) for tracking requests and bugs. Please use our [slack](https://qiskit.slack.com) for discussion and simple questions. To join our Slack community use the [link](https://qiskit.slack.com/join/shared_invite/zt-fybmq791-hYRopcSH6YetxycNPXgv~A#/). For questions that are more suited for a forum, we use the Qiskit tag in the [Stack Exchange](https://quantumcomputing.stackexchange.com/questions/tagged/qiskit). ## Next Steps -Now you're set up and ready to check out some of the other examples from our -[Qiskit IQX Tutorials](https://github.com/Qiskit/qiskit-tutorials/tree/master/tutorials/simulators) or [Qiskit Community Tutorials](https://github.com/Qiskit/qiskit-community-tutorials/tree/master/aer) repositories. +Now you're set up and ready to check out some of the other examples from the [Aer documentation](https://qiskit.org/ecosystem/aer/). ## Authors and Citation -Qiskit Aer is the work of [many people](https://github.com/Qiskit/qiskit-aer/graphs/contributors) who contribute -to the project at different levels. If you use Qiskit, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit-terra/blob/main/CITATION.bib). +Aer is the work of [many people](https://github.com/Qiskit/qiskit-aer/graphs/contributors) who contribute to the project at different levels. +If you use Qiskit, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit/blob/main/CITATION.bib). ## License diff --git a/constraints.txt b/constraints.txt index 1f3bd7a329..4fe82241ed 100644 --- a/constraints.txt +++ b/constraints.txt @@ -3,10 +3,6 @@ astroid==2.3.3 six>1.10,<=1.14 numpy>=1.16.3,<1.25 scipy>=1.0 -# stevedore, used by Terra currently (as of 3.4.0) issues deprecation warnings -# with modern importlib-metadata (4.8.1). importlib-metadata is only needed on -# Python <3.8. -importlib-metadata==4.6.4 # Jinja2 3.1.0 is incompatible with sphinx and/or jupyter until they are updated # to work with the new jinja version (the jinja maintainers aren't going to diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index e4d661a008..f819fa6703 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -11,39 +11,27 @@ :no-members: :no-inherited-members: :no-special-members: + :show-inheritance: - {% block attributes_summary %} +{% block attributes_summary %} {% if attributes %} - .. rubric:: Attributes - - .. autosummary:: - :toctree: ../stubs/ - {% for item in all_attributes %} - {%- if not item.startswith('_') %} - {{ name }}.{{ item }} - {%- endif -%} - {%- endfor %} + {% for item in all_attributes %} + {%- if not item.startswith('_') %} + .. autoattribute:: {{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} {% endif %} - {% endblock %} +{% endblock %} - {% block methods_summary %} +{% block methods_summary %} {% if methods %} - .. rubric:: Methods - - .. autosummary:: - :toctree: ../stubs/ {% for item in all_methods %} {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} - {{ name }}.{{ item }} - {%- endif -%} - {%- endfor %} - {% for item in inherited_members %} - {%- if item in ['__call__', '__mul__', '__getitem__', '__len__'] %} - {{ name }}.{{ item }} + .. automethod:: {{ name }}.{{ item }} {%- endif -%} {%- endfor %} {% endif %} - {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/docs/_templates/autosummary/class_no_inherited_members.rst b/docs/_templates/autosummary/class_no_inherited_members.rst new file mode 100644 index 0000000000..6ed7e5c62d --- /dev/null +++ b/docs/_templates/autosummary/class_no_inherited_members.rst @@ -0,0 +1,41 @@ +{# This is identical to class.rst, except for the filtering of the inherited_members. -#} + +{% if referencefile %} +.. include:: {{ referencefile }} +{% endif %} + +{{ objname }} +{{ underline }} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :no-members: + :no-inherited-members: + :no-special-members: + :show-inheritance: + +{% block attributes_summary %} + {% if attributes %} + .. rubric:: Attributes + {% for item in all_attributes %} + {%- if not item.startswith('_') %} + .. autoattribute:: {{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} + {% endif %} +{% endblock %} + +{% block methods_summary %} + {% if methods %} + .. rubric:: Methods + {% for item in all_methods %} + {%- if item not in inherited_members %} + {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} + .. automethod:: {{ name }}.{{ item }} + {%- endif -%} + {%- endif -%} + {%- endfor %} + + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 9f4cb9514f..0a7e0af317 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,9 +45,9 @@ author = 'Qiskit Development Team' # The short X.Y version -version = '0.13.0' +version = '0.14.0' # The full version, including alpha/beta/rc tags -release = '0.13.0' +release = '0.14.0' templates_path = ['_templates'] @@ -74,7 +74,7 @@ 'sphinx.ext.intersphinx', 'nbsphinx', "sphinx_design", - 'qiskit_sphinx_theme' + 'qiskit_sphinx_theme', ] # ----------------------------------------------------------------------------- @@ -138,19 +138,11 @@ # a list of builtin themes. # -html_theme = "qiskit_sphinx_theme" +html_theme = "qiskit-ecosystem" +html_title = f"{project} {release}" -html_logo = 'images/logo.png' -#html_sidebars = {'**': ['globaltoc.html']} html_last_updated_fmt = '%Y/%m/%d' -html_theme_options = { - 'logo_only': True, - 'display_version': True, - 'prev_next_buttons_location': 'bottom', - 'style_external_links': True, -} - autoclass_content = 'both' intersphinx_mapping = { "matplotlib": ("https://matplotlib.org/stable/", None), diff --git a/docs/index.rst b/docs/index.rst index 4c45d3da72..6235a75d09 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,6 +15,7 @@ https://github.com/Qiskit/qiskit-aer .. toctree:: :hidden: + Home Getting Started API Documentation Tutorials diff --git a/docs/tutorials/1_aer_provider.ipynb b/docs/tutorials/1_aer_provider.ipynb index 9e165a5701..0921311439 100755 --- a/docs/tutorials/1_aer_provider.ipynb +++ b/docs/tutorials/1_aer_provider.ipynb @@ -772,7 +772,7 @@ { "data": { "text/html": [ - "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ignis0.7.1
qiskit-ibmq-provider0.20.0
qiskit0.41.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Wed Feb 15 14:35:41 2023 JST
" + "

Version Information

Qiskit SoftwareVersion
qiskit0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ignis0.7.1
qiskit-ibmq-provider0.20.0
qiskit0.41.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Wed Feb 15 14:35:41 2023 JST
" ], "text/plain": [ "" diff --git a/docs/tutorials/2_device_noise_simulation.ipynb b/docs/tutorials/2_device_noise_simulation.ipynb index aef129393c..518ee69899 100755 --- a/docs/tutorials/2_device_noise_simulation.ipynb +++ b/docs/tutorials/2_device_noise_simulation.ipynb @@ -210,7 +210,7 @@ { "data": { "text/html": [ - "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.0.dev0+397a639
qiskit-aer0.10.4
System information
Python version3.10.4
Python compilerClang 12.0.0
Python buildmain, Mar 31 2022 03:38:35
OSDarwin
CPUs2
Memory (Gb)8.0
Thu Jul 14 10:20:15 2022 +08
" + "

Version Information

Qiskit SoftwareVersion
qiskit0.22.0.dev0+397a639
qiskit-aer0.10.4
System information
Python version3.10.4
Python compilerClang 12.0.0
Python buildmain, Mar 31 2022 03:38:35
OSDarwin
CPUs2
Memory (Gb)8.0
Thu Jul 14 10:20:15 2022 +08
" ], "text/plain": [ "" diff --git a/docs/tutorials/3_building_noise_models.ipynb b/docs/tutorials/3_building_noise_models.ipynb index 771fbff7fe..572e4564a5 100644 --- a/docs/tutorials/3_building_noise_models.ipynb +++ b/docs/tutorials/3_building_noise_models.ipynb @@ -845,7 +845,7 @@ { "data": { "text/html": [ - "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ibmq-provider0.19.2
qiskit0.40.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Tue Feb 07 10:30:00 2023 JST
" + "

Version Information

Qiskit SoftwareVersion
qiskit0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ibmq-provider0.19.2
qiskit0.40.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Tue Feb 07 10:30:00 2023 JST
" ], "text/plain": [ "" diff --git a/docs/tutorials/5_noise_transformation.ipynb b/docs/tutorials/5_noise_transformation.ipynb index 9b9547c7db..ba8d9034a2 100755 --- a/docs/tutorials/5_noise_transformation.ipynb +++ b/docs/tutorials/5_noise_transformation.ipynb @@ -318,7 +318,7 @@ { "data": { "text/html": [ - "

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ignis0.7.1
qiskit-ibmq-provider0.20.0
qiskit0.41.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Wed Feb 15 14:17:23 2023 JST
" + "

Version Information

Qiskit SoftwareVersion
qiskit0.24.0.dev0+dba2eff
qiskit-aer0.11.2
qiskit-ignis0.7.1
qiskit-ibmq-provider0.20.0
qiskit0.41.0
System information
Python version3.8.11
Python compilerClang 12.0.5 (clang-1205.0.22.11)
Python builddefault, Jul 27 2021 10:46:38
OSDarwin
CPUs8
Memory (Gb)64.0
Wed Feb 15 14:17:23 2023 JST
" ], "text/plain": [ "" diff --git a/pyproject.toml b/pyproject.toml index 8bcfe1bdce..6c9699845a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ build-backend = "setuptools.build_meta" [tool.cibuildwheel] manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" -skip = "pp* cp36* cp37* *musllinux*" +skip = "pp* cp36* cp37* cp312* *musllinux*" test-skip = "cp310-win32 cp310-manylinux_i686 cp311-win32 cp311-manylinux_i686" test-command = "python {project}/tools/verify_wheels.py" # We need to use pre-built versions of Numpy and Scipy in the tests; they have a diff --git a/qiskit_aer/VERSION.txt b/qiskit_aer/VERSION.txt index 54d1a4f2a4..a803cc227f 100644 --- a/qiskit_aer/VERSION.txt +++ b/qiskit_aer/VERSION.txt @@ -1 +1 @@ -0.13.0 +0.14.0 diff --git a/qiskit_aer/__init__.py b/qiskit_aer/__init__.py index 0c3aac5b18..ae552a3e40 100644 --- a/qiskit_aer/__init__.py +++ b/qiskit_aer/__init__.py @@ -78,8 +78,8 @@ if sys.version_info < (3, 8): warnings.warn( - "Using Qiskit Aer with Python 3.7 is deprecated as of the 0.12.0 release. " - "Support for running Qiskit Aer with Python 3.7 will be removed in a future " + "Using Aer with Python 3.7 is deprecated as of the 0.12.0 release. " + "Support for running Aer with Python 3.7 will be removed in a future " "release", DeprecationWarning, ) diff --git a/qiskit_aer/aererror.py b/qiskit_aer/aererror.py index d1ffa74eab..596439d607 100644 --- a/qiskit_aer/aererror.py +++ b/qiskit_aer/aererror.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. """ -Exception for errors raised by Qiskit Aer simulators backends. +Exception for errors raised by Aer simulators backends. """ from qiskit import QiskitError diff --git a/qiskit_aer/aerprovider.py b/qiskit_aer/aerprovider.py index 3f1b08e98a..915adc8e55 100644 --- a/qiskit_aer/aerprovider.py +++ b/qiskit_aer/aerprovider.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. # pylint: disable=invalid-name -"""Provider for Qiskit Aer backends.""" +"""Provider for Aer backends.""" from qiskit.providers import ProviderV1 as Provider @@ -24,7 +24,7 @@ class AerProvider(Provider): - """Provider for Qiskit Aer backends.""" + """Provider for Aer backends.""" _BACKENDS = None diff --git a/qiskit_aer/backends/aer_compiler.py b/qiskit_aer/backends/aer_compiler.py index 0c04c1f831..bbb2e18a25 100644 --- a/qiskit_aer/backends/aer_compiler.py +++ b/qiskit_aer/backends/aer_compiler.py @@ -21,8 +21,10 @@ from concurrent.futures import Executor import numpy as np -from qiskit.circuit import QuantumCircuit, Clbit, ParameterExpression -from qiskit.extensions import Initialize +from qiskit.circuit import QuantumCircuit, Clbit, ClassicalRegister, ParameterExpression +from qiskit.circuit.classical.expr import Expr, Unary, Binary, Var, Value, ExprVisitor, iter_vars +from qiskit.circuit.classical.types import Bool, Uint +from qiskit.circuit.library import Initialize from qiskit.providers.options import Options from qiskit.pulse import Schedule, ScheduleBlock from qiskit.circuit.controlflow import ( @@ -40,7 +42,21 @@ from qiskit_aer.noise import NoiseModel # pylint: disable=import-error, no-name-in-module -from qiskit_aer.backends.controller_wrappers import AerCircuit, AerConfig +from qiskit_aer.backends.controller_wrappers import ( + AerUnaryExpr, + AerUnaryOp, + AerBinaryExpr, + AerBinaryOp, + AerUintValue, + AerBoolValue, + AerUint, + AerBool, + AerCast, + AerVar, + AerCircuit, + AerConfig, +) + from .backend_utils import circuit_optypes from ..library.control_flow_instructions import AerMark, AerJump @@ -83,7 +99,9 @@ def compile(self, circuits, basis_gates=None, optypes=None): circuit = self._inline_initialize(circuit, compiled_optypes[idx]) if self._is_dynamic(circuit, compiled_optypes[idx]): compiled_circ = transpile( - self._inline_circuit(circuit, None, None), basis_gates=basis_gates + self._inline_circuit(circuit, None, None), + basis_gates=basis_gates, + optimization_level=0, ) compiled_circuits.append(compiled_circ) # Recompute optype for compiled circuit @@ -199,12 +217,36 @@ def _inline_circuit(self, circ, continue_label, break_label, bit_map=None): return ret - def _convert_c_if_args(self, cond_tuple, bit_map): + def _convert_jump_conditional(self, cond_tuple, bit_map): """Convert a condition tuple according to the wire map.""" - if isinstance(cond_tuple[0], Clbit): + if isinstance(cond_tuple, Expr): + return cond_tuple + elif isinstance(cond_tuple[0], Clbit): return (bit_map[cond_tuple[0]], cond_tuple[1]) - # ClassicalRegister conditions should already be in the outer circuit. - return cond_tuple + elif isinstance(cond_tuple[0], ClassicalRegister): + # ClassicalRegister conditions should already be in the outer circuit. + return cond_tuple + elif isinstance(cond_tuple[0], Var): + if isinstance(cond_tuple[0].var, Clbit): + expr = Var(bit_map[cond_tuple[0].var], cond_tuple[0].type) + elif isinstance(cond_tuple[0].var, ClassicalRegister): + expr = Var([bit_map[clbit] for clbit in cond_tuple[0].var], cond_tuple[0].type) + else: + raise AerError( + f"jump condition does not support this tyep of Var: {cond_tuple[0]}." + ) + return (expr, cond_tuple[1]) + + raise AerError(f"jump condition does not support {cond_tuple[0].__class__}.") + + def _list_clbit_from_expr(self, bit_map, expr): + ret = set() + for var in iter_vars(expr): + if isinstance(var.var, Clbit): + ret.add(bit_map[var.var]) + elif isinstance(var.var, ClassicalRegister): + ret.update(bit_map[bit] for bit in var.var) + return ret def _inline_for_loop_op(self, instruction, parent, bit_map): """inline for_loop body while iterating its indexset""" @@ -229,7 +271,7 @@ def _inline_for_loop_op(self, instruction, parent, bit_map): continue_label = f"{loop_name}_{index}" inlined_body = self._inline_circuit(body, continue_label, break_label, inner_bit_map) if loop_parameter is not None: - inlined_body = inlined_body.bind_parameters({loop_parameter: index}) + inlined_body = inlined_body.assign_parameters({loop_parameter: index}) parent.append(inlined_body, qargs, cargs) parent.append(AerMark(continue_label, len(qargs), len(cargs)), qargs, cargs) @@ -238,7 +280,7 @@ def _inline_for_loop_op(self, instruction, parent, bit_map): def _inline_while_loop_op(self, instruction, parent, bit_map): """inline while_loop body with jump and mark instructions""" - condition_tuple = self._convert_c_if_args(instruction.operation.condition, bit_map) + condition_tuple = self._convert_jump_conditional(instruction.operation.condition, bit_map) (body,) = instruction.operation.params self._last_flow_id += 1 @@ -262,23 +304,20 @@ def _inline_while_loop_op(self, instruction, parent, bit_map): ) qargs = [bit_map[q] for q in instruction.qubits] cargs = [bit_map[c] for c in instruction.clbits] - mark_cargs = cargs.copy() - mark_cargs.extend( - bit_map[c] - for c in ( - ( - {condition_tuple[0]} - if isinstance(condition_tuple[0], Clbit) - else set(condition_tuple[0]) - ) - - set(instruction.clbits) - ) - ) - c_if_args = self._convert_c_if_args(condition_tuple, bit_map) + + if isinstance(condition_tuple, Expr): + mark_cargs = self._list_clbit_from_expr(bit_map, condition_tuple) + elif isinstance(condition_tuple[0], Clbit): + mark_cargs = {bit_map[condition_tuple[0]]} + else: + mark_cargs = {bit_map[c] for c in condition_tuple[0]} + mark_cargs = set(cargs).union(mark_cargs) - set(instruction.clbits) + + c_if_args = self._convert_jump_conditional(condition_tuple, bit_map) parent.append(AerMark(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) parent.append( - AerJump(loop_start_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), + AerJump(loop_start_label, len(qargs), len(mark_cargs)).set_conditional(c_if_args), qargs, mark_cargs, ) @@ -304,22 +343,18 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b else: if_else_label = if_end_label - c_if_args = self._convert_c_if_args(condition_tuple, bit_map) + c_if_args = self._convert_jump_conditional(condition_tuple, bit_map) qargs = [bit_map[q] for q in instruction.qubits] cargs = [bit_map[c] for c in instruction.clbits] - mark_cargs = cargs.copy() - mark_cargs.extend( - bit_map[c] - for c in ( - ( - {condition_tuple[0]} - if isinstance(condition_tuple[0], Clbit) - else set(condition_tuple[0]) - ) - - set(instruction.clbits) - ) - ) + + if isinstance(condition_tuple, Expr): + mark_cargs = self._list_clbit_from_expr(bit_map, condition_tuple) + elif isinstance(condition_tuple[0], Clbit): + mark_cargs = {bit_map[condition_tuple[0]]} + else: + mark_cargs = {bit_map[c] for c in condition_tuple[0]} + mark_cargs = set(cargs).union(mark_cargs) - set(instruction.clbits) true_bit_map = { inner: bit_map[outer] @@ -330,7 +365,9 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b } parent.append( - AerJump(if_true_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), qargs, mark_cargs + AerJump(if_true_label, len(qargs), len(mark_cargs)).set_conditional(c_if_args), + qargs, + mark_cargs, ) parent.append(AerJump(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) parent.append(AerMark(if_true_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) @@ -366,11 +403,14 @@ def _inline_switch_case_op(self, instruction, continue_label, break_label, paren qargs = [bit_map[q] for q in instruction.qubits] cargs = [bit_map[c] for c in instruction.clbits] - mark_cargs = ( - set(cargs + [bit_map[instruction.operation.target]]) - if isinstance(instruction.operation.target, Clbit) - else set(cargs + [bit_map[c] for c in instruction.operation.target]) - ) - set(instruction.clbits) + + if isinstance(instruction.operation.target, Clbit): + target_clbits = {bit_map[instruction.operation.target]} + elif isinstance(instruction.operation.target, Expr): + target_clbits = self._list_clbit_from_expr(bit_map, instruction.operation.target) + else: + target_clbits = {bit_map[c] for c in instruction.operation.target} + mark_cargs = set(cargs).union(target_clbits) - set(instruction.clbits) switch_end_label = f"{switch_name}_end" case_default_label = None @@ -383,7 +423,9 @@ def _inline_switch_case_op(self, instruction, continue_label, break_label, paren case_data = CaseData( label=f"{switch_name}_{i}", args_list=[ - self._convert_c_if_args((instruction.operation.target, switch_val), bit_map) + self._convert_jump_conditional( + (instruction.operation.target, switch_val), bit_map + ) if switch_val != CASE_DEFAULT else [] for switch_val in case[0] @@ -407,8 +449,17 @@ def _inline_switch_case_op(self, instruction, continue_label, break_label, paren for case_data in case_data_list: for case_args in case_data.args_list: if len(case_args) > 0: + if isinstance(case_args[0], Expr): + case_args = Binary( + Binary.Op.EQUAL, + case_args[0], + Value(case_args[1], case_args[0].type), + Bool(), + ) parent.append( - AerJump(case_data.label, len(qargs), len(mark_cargs)).c_if(*case_args), + AerJump(case_data.label, len(qargs), len(mark_cargs)).set_conditional( + case_args + ), qargs, mark_cargs, ) @@ -580,7 +631,11 @@ def assemble_circuit(circuit: QuantumCircuit): for creg in circuit.cregs: creg_sizes.append([creg.name, creg.size]) - is_conditional = any(getattr(inst.operation, "condition", None) for inst in circuit.data) + is_conditional = any( + getattr(inst.operation, "condition_expr", None) + or getattr(inst.operation, "condition", None) + for inst in circuit.data + ) header = QobjExperimentHeader( n_qubits=num_qubits, @@ -607,6 +662,7 @@ def assemble_circuit(circuit: QuantumCircuit): # to the conditional instruction to map the creg ?= val condition # onto a gating register bit. conditional_reg = -1 + conditional_expr = None if hasattr(inst.operation, "condition") and inst.operation.condition: ctrl_reg, ctrl_val = inst.operation.condition mask = 0 @@ -623,16 +679,124 @@ def assemble_circuit(circuit: QuantumCircuit): aer_circ.bfunc(f"0x{mask:X}", f"0x{val:X}", "==", conditional_reg) num_of_aer_ops += 1 max_conditional_idx += 1 + elif hasattr(inst.operation, "condition_expr") and inst.operation.condition_expr: + conditional_expr = inst.operation.condition_expr num_of_aer_ops += _assemble_op( - aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg + circuit, + aer_circ, + inst, + qubit_indices, + clbit_indices, + is_conditional, + conditional_reg, + conditional_expr, ) index_map.append(num_of_aer_ops - 1) return aer_circ, index_map -def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg): +def _assemble_type(expr_type): + if isinstance(expr_type, Uint): + return AerUint(expr_type.width) + elif isinstance(expr_type, Bool): + return AerBool() + else: + raise AerError(f"unknown type: {expr_type.__class__}") + + +def _assemble_clbit_indices(circ, c): + if isinstance(c, (ClassicalRegister, list)): + return [circ.find_bit(cbit).index for cbit in c] + elif isinstance(c, Clbit): + return [circ.find_bit(c).index] + else: + raise AerError(f"unknown clibt list: {c.__class__}") + + +def _assemble_unary_operator(op): + if op is Unary.Op.BIT_NOT: + return AerUnaryOp.BitNot + elif op is Unary.Op.LOGIC_NOT: + return AerUnaryOp.LogicNot + else: + raise AerError(f"unknown op: {op}") + + +_BINARY_OP_MAPPING = { + Binary.Op.BIT_AND: AerBinaryOp.BitAnd, + Binary.Op.BIT_OR: AerBinaryOp.BitOr, + Binary.Op.BIT_XOR: AerBinaryOp.BitXor, + Binary.Op.LOGIC_AND: AerBinaryOp.LogicAnd, + Binary.Op.LOGIC_OR: AerBinaryOp.LogicOr, + Binary.Op.EQUAL: AerBinaryOp.Equal, + Binary.Op.NOT_EQUAL: AerBinaryOp.NotEqual, + Binary.Op.LESS: AerBinaryOp.Less, + Binary.Op.LESS_EQUAL: AerBinaryOp.LessEqual, + Binary.Op.GREATER: AerBinaryOp.Greater, + Binary.Op.GREATER_EQUAL: AerBinaryOp.GreaterEqual, +} + + +def _assemble_binary_operator(op): + if op in _BINARY_OP_MAPPING: + return _BINARY_OP_MAPPING[op] + else: + raise AerError(f"unknown op: {op}") + + +class _AssembleExprImpl(ExprVisitor): + """Convert from Expr objects to corresponding objects.""" + + def __init__(self, circuit): + self.circuit = circuit + + def visit_value(self, node, /): + """return Aer's value types.""" + # pylint: disable=unused-variable + if isinstance(node.type, Uint): + return AerUintValue(node.type.width, node.value) + elif isinstance(node.type, Bool): + return AerBoolValue(node.value) + else: + raise AerError(f"invalid value type is specified: {node.type.__class__}") + + def visit_var(self, node, /): + return AerVar(_assemble_type(node.type), _assemble_clbit_indices(self.circuit, node.var)) + + def visit_cast(self, node, /): + return AerCast(_assemble_type(node.type), node.operand.accept(self)) + + def visit_unary(self, node, /): + return AerUnaryExpr(_assemble_unary_operator(node.op), node.operand.accept(self)) + + def visit_binary(self, node, /): + return AerBinaryExpr( + _assemble_binary_operator(node.op), + node.left.accept(self), + node.right.accept(self), + ) + + def visit_generic(self, node, /): + raise AerError(f"unsupported expression is used: {node.__class__}") + + +def _check_no_conditional(inst_name, conditional_reg): + if conditional_reg >= 0: + raise AerError(f"instruction {inst_name} does not support conditional") + + +def _assemble_op( + circ, + aer_circ, + inst, + qubit_indices, + clbit_indices, + is_conditional, + conditional_reg, + conditional_expr, +): operation = inst.operation qubits = [qubit_indices[qubit] for qubit in inst.qubits] clbits = [clbit_indices[clbit] for clbit in inst.clbits] @@ -648,6 +812,8 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c copied = True params[i] = 0.0 + aer_cond_expr = conditional_expr.accept(_AssembleExprImpl(circ)) if conditional_expr else None + num_of_aer_ops = 1 # fmt: off if name in { @@ -657,28 +823,33 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c "rx", "rxx", "ry", "ryy", "rz", "rzx", "rzz", "s", "sdg", "swap", "sx", "sxdg", "t", "tdg", "u", "x", "y", "z", "u1", "u2", "u3", "cu", "cu1", "cu2", "cu3", }: - aer_circ.gate(name, qubits, params, [], conditional_reg, label if label else name) + aer_circ.gate(name, qubits, params, [], conditional_reg, aer_cond_expr, + label if label else name) elif name == "measure": if is_conditional: aer_circ.measure(qubits, clbits, clbits) else: aer_circ.measure(qubits, clbits, []) elif name == "reset": - aer_circ.reset(qubits) + aer_circ.reset(qubits, conditional_reg) elif name == "diagonal": - aer_circ.diagonal(qubits, params, label if label else "diagonal") + aer_circ.diagonal(qubits, params, conditional_reg, label if label else "diagonal") elif name == "unitary": - aer_circ.unitary(qubits, params[0], conditional_reg, label if label else "unitary") + aer_circ.unitary(qubits, params[0], conditional_reg, aer_cond_expr, + label if label else "unitary") elif name == "pauli": - aer_circ.gate(name, qubits, [], params, conditional_reg, label if label else name) + aer_circ.gate(name, qubits, [], params, conditional_reg, aer_cond_expr, + label if label else name) elif name == "initialize": + _check_no_conditional(name, conditional_reg) aer_circ.initialize(qubits, params) elif name == "roerror": + _check_no_conditional(name, conditional_reg) aer_circ.roerror(qubits, params) elif name == "multiplexer": - aer_circ.multiplexer(qubits, params, conditional_reg, label if label else name) + aer_circ.multiplexer(qubits, params, conditional_reg, aer_cond_expr, label if label else name) elif name == "kraus": - aer_circ.kraus(qubits, params, conditional_reg) + aer_circ.kraus(qubits, params, conditional_reg, aer_cond_expr) elif name in { "save_statevector", "save_statevector_dict", @@ -692,10 +863,13 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c "save_state", "save_stabilizer", }: + _check_no_conditional(name, conditional_reg) aer_circ.save_state(qubits, name, operation._subtype, label if label else name) elif name in {"save_amplitudes", "save_amplitudes_sq"}: + _check_no_conditional(name, conditional_reg) aer_circ.save_amplitudes(qubits, name, params, operation._subtype, label if label else name) elif name in ("save_expval", "save_expval_var"): + _check_no_conditional(name, conditional_reg) paulis = [] coeff_reals = [] coeff_imags = [] @@ -713,27 +887,35 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c label if label else name, ) elif name == "set_statevector": + _check_no_conditional(name, conditional_reg) aer_circ.set_statevector(qubits, params) elif name == "set_unitary": + _check_no_conditional(name, conditional_reg) aer_circ.set_unitary(qubits, params) elif name == "set_density_matrix": + _check_no_conditional(name, conditional_reg) aer_circ.set_density_matrix(qubits, params) elif name == "set_stabilizer": + _check_no_conditional(name, conditional_reg) aer_circ.set_clifford(qubits, params) elif name == "set_superop": + _check_no_conditional(name, conditional_reg) aer_circ.set_superop(qubits, params) elif name == "set_matrix_product_state": + _check_no_conditional(name, conditional_reg) aer_circ.set_matrix_product_state(qubits, params) elif name == "superop": - aer_circ.superop(qubits, params[0], conditional_reg) + aer_circ.superop(qubits, params[0], conditional_reg, aer_cond_expr) elif name == "barrier": + _check_no_conditional(name, conditional_reg) num_of_aer_ops = 0 elif name == "jump": - aer_circ.jump(qubits, params, conditional_reg) + aer_circ.jump(qubits, params, conditional_reg, aer_cond_expr) elif name == "mark": + _check_no_conditional(name, conditional_reg) aer_circ.mark(qubits, params) elif name == "qerror_loc": - aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg) + aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg, aer_cond_expr) elif name in ("for_loop", "while_loop", "if_else"): raise AerError( "control-flow instructions must be converted " f"to jump and mark instructions: {name}" diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index 6f224e49ca..9638bd8a71 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Qiskit Aer qasm simulator backend. +Aer qasm simulator backend. """ import copy @@ -31,7 +31,7 @@ BASIS_GATES, ) -# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import aer_controller_execute logger = logging.getLogger(__name__) @@ -519,6 +519,8 @@ class AerSimulator(AerBackend): "while_loop", "break_loop", "continue_loop", + "reset", + "switch_case", ] ), "density_matrix": sorted( @@ -541,6 +543,8 @@ class AerSimulator(AerBackend): "while_loop", "break_loop", "continue_loop", + "reset", + "switch_case", ] ), "matrix_product_state": sorted( @@ -565,6 +569,8 @@ class AerSimulator(AerBackend): "while_loop", "break_loop", "continue_loop", + "reset", + "switch_case", ] ), "stabilizer": sorted( @@ -586,6 +592,8 @@ class AerSimulator(AerBackend): "while_loop", "break_loop", "continue_loop", + "reset", + "switch_case", ] ), "extended_stabilizer": sorted( @@ -594,6 +602,7 @@ class AerSimulator(AerBackend): "qerror_loc", "roerror", "save_statevector", + "reset", ] ), "unitary": sorted( @@ -601,6 +610,7 @@ class AerSimulator(AerBackend): "save_state", "save_unitary", "set_unitary", + "reset", ] ), "superop": sorted( @@ -612,6 +622,7 @@ class AerSimulator(AerBackend): "save_state", "save_superop", "set_superop", + "reset", ] ), "tensor_network": sorted( @@ -633,6 +644,8 @@ class AerSimulator(AerBackend): "save_statevector_dict", "set_statevector", "set_density_matrix", + "reset", + "switch_case", ] ), } @@ -685,17 +698,17 @@ class AerSimulator(AerBackend): _AVAILABLE_DEVICES = None - def __init__(self, configuration=None, properties=None, provider=None, **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, target=None, **backend_options + ): self._controller = aer_controller_execute() # Update available methods and devices for class if AerSimulator._AVAILABLE_DEVICES is None: - AerSimulator._AVAILABLE_DEVICES = available_devices( - self._controller, AerSimulator._SIMULATION_DEVICES - ) + AerSimulator._AVAILABLE_DEVICES = available_devices(self._controller) if AerSimulator._AVAILABLE_METHODS is None: AerSimulator._AVAILABLE_METHODS = available_methods( - self._controller, AerSimulator._SIMULATION_METHODS, AerSimulator._AVAILABLE_DEVICES + AerSimulator._SIMULATION_METHODS, AerSimulator._AVAILABLE_DEVICES ) # Default configuration @@ -707,7 +720,11 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend self._cached_basis_gates = self._BASIS_GATES["automatic"] super().__init__( - configuration, properties=properties, provider=provider, backend_options=backend_options + configuration, + properties=properties, + provider=provider, + target=target, + backend_options=backend_options, ) @classmethod @@ -788,7 +805,7 @@ def __repr__(self): pad = " " * (len(self.__class__.__name__) + 1) return f"{display[:-1]}\n{pad}noise_model={repr(noise_model)})" - def name(self): + def _name(self): """Format backend name string for simulator""" name = self._configuration.backend_name method = getattr(self.options, "method", None) @@ -803,6 +820,11 @@ def name(self): def from_backend(cls, backend, **options): """Initialize simulator from backend.""" if isinstance(backend, BackendV2): + if backend.description is None: + description = "created by AerSimulator.from_backend" + else: + description = backend.description + configuration = QasmBackendConfiguration( backend_name=f"'aer_simulator({backend.name})", backend_version=backend.backend_version, @@ -817,8 +839,10 @@ def from_backend(cls, backend, **options): max_shots=int(1e6), coupling_map=list(backend.coupling_map.get_edges()), max_experiments=backend.max_circuits, + description=description, ) properties = target_to_backend_properties(backend.target) + target = backend.target elif isinstance(backend, BackendV1): # Get configuration and properties from backend configuration = copy.copy(backend.configuration()) @@ -827,6 +851,8 @@ def from_backend(cls, backend, **options): # Customize configuration name name = configuration.backend_name configuration.backend_name = f"aer_simulator({name})" + + target = None else: raise TypeError( "The backend argument requires a BackendV2 or BackendV1 object, " @@ -843,7 +869,7 @@ def from_backend(cls, backend, **options): options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, properties=properties, **options) + sim = cls(configuration=configuration, properties=properties, target=target, **options) return sim def available_methods(self): @@ -870,7 +896,7 @@ def configuration(self): ] config.basis_gates = self._cached_basis_gates + config.custom_instructions # Update simulator name - config.backend_name = self.name() + config.backend_name = self._name() return config def _execute_circuits(self, aer_circuits, noise_model, config): diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 7266572ae9..36545ffe8c 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Qiskit Aer qasm simulator backend. +Aer qasm simulator backend. """ import copy @@ -23,19 +23,22 @@ from qiskit.circuit import QuantumCircuit, ParameterExpression, Delay from qiskit.compiler import assemble -from qiskit.providers import BackendV1 as Backend +from qiskit.providers import BackendV2 as Backend +from qiskit.providers import convert_to_target from qiskit.providers.models import BackendStatus from qiskit.pulse import Schedule, ScheduleBlock from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result +from qiskit.transpiler import CouplingMap from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj from ..noise.noise_model import NoiseModel, QuantumErrorLocation from ..noise.errors.quantum_error import QuantumChannelInstruction from .aer_compiler import compile_circuit, assemble_circuits, generate_aer_config from .backend_utils import format_save_type, circuit_optypes +from .name_mapping import NAME_MAPPING -# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import AerConfig # Logger @@ -43,10 +46,10 @@ class AerBackend(Backend, ABC): - """Qiskit Aer Backend class.""" + """Aer Backend class.""" def __init__( - self, configuration, properties=None, defaults=None, backend_options=None, provider=None + self, configuration, properties=None, provider=None, target=None, backend_options=None ): """Aer class for backends. @@ -57,8 +60,8 @@ def __init__( Args: configuration (BackendConfiguration): backend configuration. properties (BackendProperties or None): Optional, backend properties. - defaults (PulseDefaults or None): Optional, backend pulse defaults. provider (Provider): Optional, provider responsible for this backend. + target (Target): initial target for backend backend_options (dict or None): Optional set custom backend options. Raises: @@ -67,21 +70,31 @@ def __init__( # Init configuration and provider in Backend configuration.simulator = True configuration.local = True - super().__init__(configuration, provider=provider) + super().__init__( + provider=provider, + name=configuration.backend_name, + description=configuration.description, + backend_version=configuration.backend_version, + ) - # Initialize backend properties and pulse defaults. + # Initialize backend properties self._properties = properties - self._defaults = defaults + self._configuration = configuration - # Custom option values for config, properties, and defaults + # Custom option values for config, properties self._options_configuration = {} - self._options_defaults = {} self._options_properties = {} + self._target = target + self._mapping = NAME_MAPPING # Set options from backend_options dictionary if backend_options is not None: self.set_options(**backend_options) + # build coupling map + if self.configuration().coupling_map is not None: + self._coupling_map = CouplingMap(self.configuration().coupling_map) + def _convert_circuit_binds(self, circuit, binds, idx_map): parameterizations = [] @@ -303,7 +316,7 @@ def configuration(self): for key, val in self._options_configuration.items(): setattr(config, key, val) # If config has custom instructions add them to - # basis gates to include them for the terra transpiler + # basis gates to include them for the qiskit transpiler if hasattr(config, "custom_instructions"): config.basis_gates = config.basis_gates + config.custom_instructions return config @@ -320,28 +333,25 @@ def properties(self): setattr(properties, key, val) return properties - def defaults(self): - """Return the simulator backend pulse defaults. + @property + def max_circuits(self): + if hasattr(self.configuration(), "max_experiments"): + return self.configuration().max_experiments + else: + return None - Returns: - PulseDefaults: The backend pulse defaults or ``None`` if the - backend does not support pulse. - """ - defaults = copy.copy(self._defaults) - for key, val in self._options_defaults.items(): - setattr(defaults, key, val) - return defaults + @property + def target(self): + if self._target is not None: + return self._target - @classmethod - def _default_options(cls): - pass + return convert_to_target(self.configuration(), self.properties(), None, NAME_MAPPING) def clear_options(self): """Reset the simulator options to default values.""" self._options = self._default_options() self._options_configuration = {} self._options_properties = {} - self._options_defaults = {} def status(self): """Return backend status. @@ -350,7 +360,7 @@ def status(self): BackendStatus: the status of the backend. """ return BackendStatus( - backend_name=self.name(), + backend_name=self.name, backend_version=self.configuration().backend_version, operational=True, pending_jobs=0, @@ -388,7 +398,7 @@ def _execute_qobj_job(self, qobj, job_id="", format_result=True): # Validate output if not isinstance(output, dict): - logger.error("%s: simulation failed.", self.name()) + logger.error("%s: simulation failed.", self.name) if output: logger.error("Output: %s", output) raise AerError("simulation terminated without returning valid output.") @@ -396,7 +406,7 @@ def _execute_qobj_job(self, qobj, job_id="", format_result=True): # Format results output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() - output["backend_name"] = self.name() + output["backend_name"] = self.name output["backend_version"] = self.configuration().backend_version # Push metadata to experiment headers @@ -454,7 +464,7 @@ def _execute_circuits_job( # Validate output if not isinstance(output, dict): - logger.error("%s: simulation failed.", self.name()) + logger.error("%s: simulation failed.", self.name) if output: logger.error("Output: %s", output) raise AerError("simulation terminated without returning valid output.") @@ -462,7 +472,7 @@ def _execute_circuits_job( # Format results output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() - output["backend_name"] = self.name() + output["backend_name"] = self.name output["backend_version"] = self.configuration().backend_version # Push metadata to experiment headers @@ -682,8 +692,6 @@ def set_option(self, key, value): self._set_configuration_option(key, value) elif hasattr(self._properties, key): self._set_properties_option(key, value) - elif hasattr(self._defaults, key): - self._set_defaults_option(key, value) else: if not hasattr(self._options, key): raise AerError(f"Invalid option {key}") @@ -715,15 +723,15 @@ def _set_properties_option(self, key, value): elif key in self._options_properties: self._options_properties.pop(key) - def _set_defaults_option(self, key, value): - """Special handling for setting backend defaults options.""" - if value is not None: - self._options_defaults[key] = value - elif key in self._options_defaults: - self._options_defaults.pop(key) - def __repr__(self): """String representation of an AerBackend.""" name = self.__class__.__name__ - display = f"'{self.name()}'" + display = f"'{self.name}'" return f"{name}({display})" + + def get_translation_stage_plugin(self): + """use custom translation method to avoid gate exchange""" + if self._target is None: + return "aer_backend_plugin" + else: + return None diff --git a/qiskit_aer/backends/backend_utils.py b/qiskit_aer/backends/backend_utils.py index 1e41c38f56..fe9b71dc14 100644 --- a/qiskit_aer/backends/backend_utils.py +++ b/qiskit_aer/backends/backend_utils.py @@ -12,20 +12,21 @@ # pylint: disable=invalid-name """ -Qiskit Aer simulator backend utils +Aer simulator backend utils """ import os from math import log2 -from qiskit.utils import local_hardware_info + +import psutil from qiskit.circuit import QuantumCircuit -from qiskit.compiler import assemble from qiskit.qobj import QasmQobjInstruction from qiskit.result import ProbDistribution from qiskit.quantum_info import Clifford + from .compatibility import Statevector, DensityMatrix, StabilizerState, Operator, SuperOp # Available system memory -SYSTEM_MEMORY_GB = local_hardware_info()["memory"] +SYSTEM_MEMORY_GB = psutil.virtual_memory().total / (1024**3) # Max number of qubits for complex double statevector # given available system memory @@ -439,40 +440,23 @@ def cpp_execute_circuits(controller, aer_circuits, noise_model, config): return controller.execute(aer_circuits, noise_model, config) -def available_methods(controller, methods, devices): - """Check available simulation methods by running a dummy circuit.""" - # Test methods are available using the controller - dummy_circ = QuantumCircuit(1) - dummy_circ.id(0) +def available_methods(methods, devices): + """Check available simulation methods""" valid_methods = [] - for device in devices: - for method in methods: - if method not in valid_methods: - qobj = assemble( - dummy_circ, optimization_level=0, shots=1, method=method, device=device - ) - result = cpp_execute_qobj(controller, qobj) - if result.get("success", False): - valid_methods.append(method) + for method in methods: + if method == "tensor_network": + if "GPU" in devices: + valid_methods.append(method) + else: + valid_methods.append(method) return tuple(valid_methods) -def available_devices(controller, devices): - """Check available simulation devices by running a dummy circuit.""" - # Test methods are available using the controller - dummy_circ = QuantumCircuit(1) - dummy_circ.id(0) - - valid_devices = [] - for device in devices: - qobj = assemble( - dummy_circ, optimization_level=0, shots=1, method="statevector", device=device - ) - result = cpp_execute_qobj(controller, qobj) - if result.get("success", False): - valid_devices.append(device) - return tuple(valid_devices) +def available_devices(controller): + """return available simulation devices""" + dev = controller.available_devices() + return tuple(dev) def add_final_save_instruction(qobj, state): diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py new file mode 100644 index 0000000000..5af58e3b07 --- /dev/null +++ b/qiskit_aer/backends/name_mapping.py @@ -0,0 +1,304 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +# pylint: disable=invalid-name +""" +Qiskit Aer simulator name mapping for Target object +""" +from qiskit.circuit import ControlledGate, Parameter +from qiskit.circuit.reset import Reset +from qiskit.circuit.library import ( + U2Gate, + RGate, + CYGate, + CZGate, + CSXGate, + CU3Gate, + CSwapGate, + PauliGate, + DiagonalGate, + UnitaryGate, + MCPhaseGate, + MCXGate, + CRXGate, + CRYGate, + CRZGate, + MCU1Gate, + MCXGrayCode, + Initialize, + UCGate, +) +from qiskit.circuit.controlflow import ( + IfElseOp, + WhileLoopOp, + ForLoopOp, + ContinueLoopOp, + BreakLoopOp, + SwitchCaseOp, +) +from qiskit.quantum_info.operators.channel.kraus import Kraus +from qiskit.quantum_info.operators.channel import SuperOp +from qiskit.quantum_info.operators.channel.quantum_channel import QuantumChannel + +from ..library import ( + SaveExpectationValue, + SaveAmplitudes, + SaveStatevectorDict, + SaveSuperOp, + SaveClifford, + SaveMatrixProductState, + SaveDensityMatrix, + SaveProbabilities, + SaveStatevector, + SetDensityMatrix, + SetUnitary, + SaveState, + SetMatrixProductState, + SaveUnitary, + SetSuperOp, + SaveExpectationValueVariance, + SaveStabilizer, + SetStatevector, + SetStabilizer, + SaveAmplitudesSquared, + SaveProbabilitiesDict, +) +from ..noise.errors import ReadoutError +from ..noise.noise_model import QuantumErrorLocation + + +class MCSXGate(ControlledGate): + """mcsx gate""" + + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcsx", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CSXGate(), + ) + + +class MCYGate(ControlledGate): + """mcy gate""" + + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcy", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CYGate(), + ) + + +class MCZGate(ControlledGate): + """mcz gate""" + + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcz", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CZGate(), + ) + + +class MCRXGate(ControlledGate): + """mcrx gate""" + + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcrx", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CRXGate(theta), + ) + + +class MCRYGate(ControlledGate): + """mcry gate""" + + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcry", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CRYGate(theta), + ) + + +class MCRZGate(ControlledGate): + """mcrz gate""" + + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcrz", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CRZGate(theta), + ) + + +class MCRGate(ControlledGate): + """mcr gate""" + + def __init__(self, theta, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcr", + 1 + num_ctrl_qubits, + [theta, phi], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=RGate(theta, phi), + ) + + +class MCU2Gate(ControlledGate): + """mcu2 gate""" + + def __init__(self, theta, lam, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu2", + 1 + num_ctrl_qubits, + [theta, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=U2Gate(theta, lam), + ) + + +class MCU3Gate(ControlledGate): + """mcu3 gate""" + + def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu3", + 1 + num_ctrl_qubits, + [theta, phi, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CU3Gate(theta, phi, lam), + ) + + +class MCUGate(ControlledGate): + """mcu gate""" + + def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu", + 1 + num_ctrl_qubits, + [theta, phi, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CU3Gate(theta, phi, lam), + ) + + +class MCSwapGate(ControlledGate): + """mcswap gate""" + + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcswap", + 2 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=CSwapGate(), + ) + + +PHI = Parameter("phi") +LAM = Parameter("lam") +NAME_MAPPING = { + "cu2": U2Gate(PHI, LAM).control(), + "pauli": PauliGate, + "diagonal": DiagonalGate, + "unitary": UnitaryGate, + "mcsx": MCSXGate, + "mcp": MCPhaseGate, + "mcphase": MCPhaseGate, + "mcu": MCUGate, + "mcu1": MCU1Gate, + "mcu2": MCU2Gate, + "mcu3": MCU3Gate, + "mcx": MCXGate, + "mcy": MCYGate, + "mcz": MCZGate, + "mcr": MCRGate, + "mcrx": MCRXGate, + "mcry": MCRYGate, + "mcrz": MCRZGate, + "mcx_gray": MCXGrayCode, + "mcswap": MCSwapGate, + "multiplexer": UCGate, + "kraus": Kraus, + "superop": SuperOp, + "initialize": Initialize, + "quantum_channel": QuantumChannel, + "save_expval": SaveExpectationValue, + "save_amplitudes": SaveAmplitudes, + "roerror": ReadoutError, + "save_statevector_dict": SaveStatevectorDict, + "save_superop": SaveSuperOp, + "save_clifford": SaveClifford, + "save_matrix_product_state": SaveMatrixProductState, + "save_density_matrix": SaveDensityMatrix, + "save_probabilities": SaveProbabilities, + "if_else": IfElseOp, + "while_loop": WhileLoopOp, + "for_loop": ForLoopOp, + "switch_case": SwitchCaseOp, + "break_loop": BreakLoopOp, + "continue_loop": ContinueLoopOp, + "save_statevector": SaveStatevector, + "set_density_matrix": SetDensityMatrix, + "qerror_loc": QuantumErrorLocation, + "set_unitary": SetUnitary, + "save_state": SaveState, + "set_matrix_product_state": SetMatrixProductState, + "save_unitary": SaveUnitary, + "set_superop": SetSuperOp, + "save_expval_var": SaveExpectationValueVariance, + "save_stabilizer": SaveStabilizer, + "set_statevector": SetStatevector, + "set_stabilizer": SetStabilizer, + "save_amplitudes_sq": SaveAmplitudesSquared, + "save_probabilities_dict": SaveProbabilitiesDict, + "save_probs_ket": SaveProbabilitiesDict, + "save_probs": SaveProbabilities, + "reset": Reset(), +} diff --git a/qiskit_aer/backends/plugin/__init__.py b/qiskit_aer/backends/plugin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py new file mode 100644 index 0000000000..73be26fcef --- /dev/null +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -0,0 +1,126 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Aer simulator backend transpiler plug-in +""" +from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin +from qiskit.transpiler import PassManager, TransformationPass +from qiskit.transpiler.passes import BasisTranslator +from qiskit.transpiler.passes import UnitarySynthesis +from qiskit.transpiler.passes import HighLevelSynthesis +from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel +from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping +from qiskit.circuit.measure import Measure +from qiskit.circuit.library import Barrier +from qiskit.circuit import ControlFlowOp +from qiskit.converters import circuit_to_dag +from qiskit_aer.backends.name_mapping import NAME_MAPPING + + +class AerBackendRebuildGateSetsFromCircuit(TransformationPass): + """custom translation class to rebuild basis gates with gates in circuit""" + + def __init__(self, config, opt_lvl): + super().__init__() + self.config = config + if opt_lvl is None: + self.optimization_level = 1 + else: + self.optimization_level = opt_lvl + self.qiskit_inst_name_map = get_standard_gate_name_mapping() + self.qiskit_inst_name_map["barrier"] = Barrier + + def _add_ops(self, dag, ops: set): + num_unsupported_ops = 0 + opnodes = dag.op_nodes() + if opnodes is None: + return num_unsupported_ops + + for node in opnodes: + if isinstance(node.op, ControlFlowOp): + for block in node.op.blocks: + num_unsupported_ops += self._add_ops(circuit_to_dag(block), ops) + if node.name in self.qiskit_inst_name_map: + ops.add(node.name) + elif node.name in self.config.target: + ops.add(node.name) + else: + num_unsupported_ops = num_unsupported_ops + 1 + return num_unsupported_ops + + def run(self, dag): + # do nothing for higher optimization level + if self.optimization_level > 1: + return dag + if self.config is None or self.config.target is None: + return dag + + # search ops in supported name mapping + ops = set() + num_unsupported_ops = self._add_ops(dag, ops) + + # if there are some unsupported node (i.e. RealAmplitudes) do nothing + if num_unsupported_ops > 0 or len(ops) < 1: + return dag + + # clear all instructions in target + self.config.target._gate_map.clear() + self.config.target._gate_name_map.clear() + self.config.target._qarg_gate_map.clear() + self.config.target._global_operations.clear() + + # rebuild gate sets from circuit + for name in ops: + if name in self.qiskit_inst_name_map: + self.config.target.add_instruction(self.qiskit_inst_name_map[name], name=name) + else: + self.config.target.add_instruction(NAME_MAPPING[name], name=name) + if "measure" not in ops: + self.config.target.add_instruction(Measure()) + self.config.basis_gates = list(self.config.target.operation_names) + + return dag + + +# This plugin should not be used outside of simulator +# TODO : this plugin should be moved to optimization stage plugin +# if Qiskit will have custom optimizaiton stage plugin interface +# in that case just return pass without Optimize1qGatesDecomposition +class AerBackendPlugin(PassManagerStagePlugin): + """custom passmanager to avoid unnecessary gate changes""" + + def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager: + return PassManager( + [ + UnitarySynthesis( + pass_manager_config.basis_gates, + approximation_degree=pass_manager_config.approximation_degree, + coupling_map=pass_manager_config.coupling_map, + backend_props=pass_manager_config.backend_properties, + plugin_config=pass_manager_config.unitary_synthesis_plugin_config, + method=pass_manager_config.unitary_synthesis_method, + target=pass_manager_config.target, + ), + HighLevelSynthesis( + hls_config=pass_manager_config.hls_config, + coupling_map=pass_manager_config.coupling_map, + target=pass_manager_config.target, + use_qubit_indices=True, + equivalence_library=sel, + basis_gates=pass_manager_config.basis_gates, + ), + BasisTranslator(sel, pass_manager_config.basis_gates, pass_manager_config.target), + AerBackendRebuildGateSetsFromCircuit( + config=pass_manager_config, opt_lvl=optimization_level + ), + ] + ) diff --git a/qiskit_aer/backends/qasm_simulator.py b/qiskit_aer/backends/qasm_simulator.py index aa0f788ec9..a36731403a 100644 --- a/qiskit_aer/backends/qasm_simulator.py +++ b/qiskit_aer/backends/qasm_simulator.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Qiskit Aer qasm simulator backend. +Aer qasm simulator backend. """ import copy @@ -33,7 +33,7 @@ map_legacy_method_config, ) -# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import aer_controller_execute logger = logging.getLogger(__name__) @@ -388,6 +388,7 @@ class QasmSimulator(AerBackend): "set_statevector", "set_density_matrix", "set_stabilizer", + "reset", ] ) @@ -443,7 +444,6 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend # Update available methods for class if QasmSimulator._AVAILABLE_METHODS is None: QasmSimulator._AVAILABLE_METHODS = available_methods( - self._controller, QasmSimulator._SIMULATION_METHODS, QasmSimulator._SIMULATION_DEVICES, ) diff --git a/qiskit_aer/backends/statevector_simulator.py b/qiskit_aer/backends/statevector_simulator.py index e7affcf1c7..9c2b67a87d 100644 --- a/qiskit_aer/backends/statevector_simulator.py +++ b/qiskit_aer/backends/statevector_simulator.py @@ -10,13 +10,14 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Qiskit Aer statevector simulator backend. +Aer statevector simulator backend. """ import copy import logging from warnings import warn -from qiskit.utils import local_hardware_info + +import psutil from qiskit.providers.options import Options from qiskit.providers.models import QasmBackendConfiguration @@ -35,7 +36,7 @@ add_final_save_op, ) -# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import aer_controller_execute # Logger @@ -230,6 +231,7 @@ class StatevectorSimulator(AerBackend): "save_amplitudes_sq", "save_state", "set_statevector", + "reset", ] ), "gates": [], @@ -252,9 +254,7 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend self._controller = aer_controller_execute() if StatevectorSimulator._AVAILABLE_DEVICES is None: - StatevectorSimulator._AVAILABLE_DEVICES = available_devices( - self._controller, StatevectorSimulator._SIMULATION_DEVICES - ) + StatevectorSimulator._AVAILABLE_DEVICES = available_devices(self._controller) if configuration is None: configuration = QasmBackendConfiguration.from_dict( @@ -354,7 +354,7 @@ def _validate(self, qobj): 1. Set shots=1. 2. Check number of qubits will fit in local memory. """ - name = self.name() + name = self.name if getattr(qobj.config, "noise_model", None) is not None: raise AerError(f"{name} does not support noise.") @@ -363,7 +363,7 @@ def _validate(self, qobj): if n_qubits > max_qubits: raise AerError( f"Number of qubits ({n_qubits}) is greater than max ({max_qubits}) " - f'for "{name}" with {int(local_hardware_info()["memory"])} GB system memory.' + f'for "{name}" with {int(psutil.virtual_memory().total / (1024**3))} GB system memory.' ) if qobj.config.shots != 1: diff --git a/qiskit_aer/backends/unitary_simulator.py b/qiskit_aer/backends/unitary_simulator.py index 190a3eb508..ef1337173c 100644 --- a/qiskit_aer/backends/unitary_simulator.py +++ b/qiskit_aer/backends/unitary_simulator.py @@ -12,12 +12,13 @@ # pylint: disable=invalid-name """ -Qiskit Aer Unitary Simulator Backend. +Aer Unitary Simulator Backend. """ import copy import logging from warnings import warn -from qiskit.utils import local_hardware_info + +import psutil from qiskit.providers.options import Options from qiskit.providers.models import QasmBackendConfiguration @@ -36,7 +37,7 @@ map_legacy_method_config, ) -# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import aer_controller_execute # Logger @@ -218,7 +219,7 @@ class UnitarySimulator(AerBackend): "pauli", ] ), - "custom_instructions": sorted(["save_unitary", "save_state", "set_unitary"]), + "custom_instructions": sorted(["save_unitary", "save_state", "set_unitary", "reset"]), "gates": [], } @@ -239,9 +240,7 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend self._controller = aer_controller_execute() if UnitarySimulator._AVAILABLE_DEVICES is None: - UnitarySimulator._AVAILABLE_DEVICES = available_devices( - self._controller, UnitarySimulator._SIMULATION_DEVICES - ) + UnitarySimulator._AVAILABLE_DEVICES = available_devices(self._controller) if configuration is None: configuration = QasmBackendConfiguration.from_dict( @@ -341,7 +340,7 @@ def _validate(self, qobj): 2. No measurements or reset 3. Check number of qubits will fit in local memory. """ - name = self.name() + name = self.name if getattr(qobj.config, "noise_model", None) is not None: raise AerError(f"{name} does not support noise.") @@ -351,7 +350,7 @@ def _validate(self, qobj): raise AerError( f"Number of qubits ({n_qubits}) is greater than " f'max ({max_qubits}) for "{name}" with ' - f"{int(local_hardware_info()['memory'])} GB system memory." + f"{int(psutil.virtual_memory().total / (1024**3))} GB system memory." ) if qobj.config.shots != 1: logger.info('"%s" only supports 1 shot. Setting shots=1.', name) diff --git a/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp b/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp index 12f3eeba5a..943f579693 100644 --- a/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp +++ b/qiskit_aer/backends/wrappers/aer_circuit_binding.hpp @@ -40,6 +40,100 @@ using namespace AER; template void bind_aer_circuit(MODULE m) { + + py::enum_(m, "AerUnaryOp", py::arithmetic()) + .value("BitNot", Operations::UnaryOp::BitNot) + .value("LogicNot", Operations::UnaryOp::LogicNot) + .export_values(); + + py::enum_(m, "AerBinaryOp", py::arithmetic()) + .value("BitAnd", Operations::BinaryOp::BitAnd) + .value("BitOr", Operations::BinaryOp::BitOr) + .value("BitXor", Operations::BinaryOp::BitXor) + .value("LogicAnd", Operations::BinaryOp::LogicAnd) + .value("LogicOr", Operations::BinaryOp::LogicOr) + .value("Equal", Operations::BinaryOp::Equal) + .value("NotEqual", Operations::BinaryOp::NotEqual) + .value("Less", Operations::BinaryOp::Less) + .value("LessEqual", Operations::BinaryOp::LessEqual) + .value("Greater", Operations::BinaryOp::Greater) + .value("GreaterEqual", Operations::BinaryOp::GreaterEqual) + .export_values(); + + py::class_> + aer_scalar_type(m, "AerScalarType"); + + py::class_> + aer_uint(m, "AerUint"); + aer_uint.def( + py::init([](const uint_t width) { return new Operations::Uint(width); })); + + py::class_> + aer_bool(m, "AerBool"); + aer_bool.def(py::init([]() { return new Operations::Bool(); })); + + py::class_> aer_expr( + m, "AerExpr"); + + aer_expr.def("eval_bool", &Operations::CExpr::eval_bool); + aer_expr.def("eval_uint", &Operations::CExpr::eval_uint); + + py::class_> + aer_cast_expr(m, "AerCast"); + aer_cast_expr.def( + py::init([](const std::shared_ptr type, + const std::shared_ptr expr) { + return new Operations::CastExpr(type, expr); + })); + + py::class_> + aer_var_expr(m, "AerVar"); + aer_var_expr.def( + py::init([](const std::shared_ptr type, + const std::vector cbit_idxs) { + return new Operations::VarExpr(type, cbit_idxs); + })); + + py::class_> + aer_val_expr(m, "AerValue"); + + py::class_> + aer_uint_expr(m, "AerUintValue"); + aer_uint_expr.def(py::init([](const size_t width, const uint_t val) { + return new Operations::UintValue(width, val); + })); + + py::class_> + aer_bool_expr(m, "AerBoolValue"); + aer_bool_expr.def( + py::init([](const bool val) { return new Operations::BoolValue(val); })); + + py::class_> + aer_unary_expr(m, "AerUnaryExpr"); + aer_unary_expr.def( + py::init([](const Operations::UnaryOp op, + const std::shared_ptr expr) { + return new Operations::UnaryExpr(op, expr); + })); + + py::class_> + aer_binary_expr(m, "AerBinaryExpr"); + aer_binary_expr.def( + py::init([](const Operations::BinaryOp op, + const std::shared_ptr left, + const std::shared_ptr right) { + return new Operations::BinaryExpr(op, left, right); + })); + py::class_> aer_circuit(m, "AerCircuit"); aer_circuit.def(py::init()); aer_circuit.def("__repr__", [](const Circuit &circ) { @@ -49,7 +143,7 @@ void bind_aer_circuit(MODULE m) { << ", num_registers=" << circ.num_registers; ss << ", ops={"; - for (auto i = 0; i < circ.ops.size(); ++i) + for (uint_t i = 0; i < circ.ops.size(); ++i) if (i == 0) ss << circ.ops[i]; else diff --git a/qiskit_aer/backends/wrappers/aer_controller_binding.hpp b/qiskit_aer/backends/wrappers/aer_controller_binding.hpp index a692915df5..ea3b48dfae 100644 --- a/qiskit_aer/backends/wrappers/aer_controller_binding.hpp +++ b/qiskit_aer/backends/wrappers/aer_controller_binding.hpp @@ -56,6 +56,11 @@ class ControllerExecutor { return AerToPy::to_python( controller_execute(circuits, noise_model, config)); } + + py::object available_devices() { + T controller; + return AerToPy::to_python(controller.available_devices()); + } }; template @@ -100,6 +105,11 @@ void bind_aer_controller(MODULE m) { return self.execute(circuits, noise_model_native, config); }); + aer_ctrl.def("available_devices", + [aer_ctrl](ControllerExecutor &self) { + return self.available_devices(); + }); + py::class_ aer_config(m, "AerConfig"); aer_config.def(py::init()); aer_config.def_readwrite("shots", &Config::shots); diff --git a/qiskit_aer/backends/wrappers/aer_state_binding.hpp b/qiskit_aer/backends/wrappers/aer_state_binding.hpp index 45dd55bcbf..c3dd880bf4 100644 --- a/qiskit_aer/backends/wrappers/aer_state_binding.hpp +++ b/qiskit_aer/backends/wrappers/aer_state_binding.hpp @@ -130,8 +130,8 @@ void bind_aer_state(MODULE m) { size_t mat_len = (1UL << qubits.size()); auto ptr = values.unchecked<2>(); cmatrix_t mat(mat_len, mat_len); - for (auto i = 0; i < mat_len; ++i) - for (auto j = 0; j < mat_len; ++j) + for (uint_t i = 0; i < mat_len; ++i) + for (uint_t j = 0; j < mat_len; ++j) mat(i, j) = ptr(i, j); state.apply_unitary(qubits, mat); }); @@ -144,10 +144,10 @@ void bind_aer_state(MODULE m) { size_t mat_size = (1UL << control_qubits.size()); auto ptr = values.unchecked<3>(); std::vector mats; - for (auto i = 0; i < mat_size; ++i) { + for (uint_t i = 0; i < mat_size; ++i) { cmatrix_t mat(mat_len, mat_len); - for (auto j = 0; j < mat_len; ++j) - for (auto k = 0; k < mat_len; ++k) + for (uint_t j = 0; j < mat_len; ++j) + for (uint_t k = 0; k < mat_len; ++k) mat(j, k) = ptr(i, j, k); mats.push_back(mat); } diff --git a/qiskit_aer/jobs/aerjob.py b/qiskit_aer/jobs/aerjob.py index 7f309a51a5..c457a60e67 100644 --- a/qiskit_aer/jobs/aerjob.py +++ b/qiskit_aer/jobs/aerjob.py @@ -25,7 +25,7 @@ class AerJob(Job): - """AerJob class for Qiskit Aer Simulators.""" + """AerJob class for Aer Simulators.""" def __init__( self, diff --git a/qiskit_aer/jobs/aerjobset.py b/qiskit_aer/jobs/aerjobset.py index ce3d3d6229..f9fcce866c 100644 --- a/qiskit_aer/jobs/aerjobset.py +++ b/qiskit_aer/jobs/aerjobset.py @@ -37,7 +37,7 @@ class AerJobSet(Job): - """A set of :class:`~AerJob` classes for Qiskit Aer simulators. + """A set of :class:`~AerJob` classes for Aer simulators. An instance of this class is returned when you submit experiments with executor option. It provides methods that allow you to interact diff --git a/qiskit_aer/library/control_flow_instructions/jump.py b/qiskit_aer/library/control_flow_instructions/jump.py index 2239e17a8a..af411edf54 100644 --- a/qiskit_aer/library/control_flow_instructions/jump.py +++ b/qiskit_aer/library/control_flow_instructions/jump.py @@ -14,6 +14,7 @@ """ from qiskit.circuit import Instruction +from qiskit.circuit.classical.expr import Expr class AerJump(Instruction): @@ -27,3 +28,19 @@ class AerJump(Instruction): def __init__(self, jump_to, num_qubits, num_clbits=0): super().__init__("jump", num_qubits, num_clbits, [jump_to]) + self.condition_expr = None + + def set_conditional(self, cond): + """Set condition to perform this jump instruction. + + Args: + cond (Expr or tuple): `Expr` to call `eval_bool` or tuple for `c_if` + + Returns: + AerJump: jump instruction added specified condition + """ + if isinstance(cond, Expr): + self.condition_expr = cond + else: + self.c_if(*cond) + return self diff --git a/qiskit_aer/library/default_qubits.py b/qiskit_aer/library/default_qubits.py index bc446e73f9..971a8cc0d9 100644 --- a/qiskit_aer/library/default_qubits.py +++ b/qiskit_aer/library/default_qubits.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumRegister -from qiskit.extensions.exceptions import ExtensionError def default_qubits(circuit, qubits=None): @@ -27,7 +26,7 @@ def default_qubits(circuit, qubits=None): [Default: None] Raises: - ExtensionError: if default qubits fails. + ValueError: if default qubits fails. Returns: list: qubits list. @@ -37,9 +36,9 @@ def default_qubits(circuit, qubits=None): # This is needed for full register snapshots like statevector if isinstance(qubits, QuantumRegister): qubits = qubits[:] - if not qubits: + if qubits is None: qubits = list(circuit.qubits) if len(qubits) == 0: - raise ExtensionError("no qubits for snapshot") + raise ValueError("no qubits for snapshot") return qubits diff --git a/qiskit_aer/library/save_instructions/save_amplitudes.py b/qiskit_aer/library/save_instructions/save_amplitudes.py index bcc12383d1..5d01945fba 100644 --- a/qiskit_aer/library/save_instructions/save_amplitudes.py +++ b/qiskit_aer/library/save_instructions/save_amplitudes.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit -from qiskit.extensions.exceptions import ExtensionError from .save_data import SaveSingleData, SaveAverageData from ..default_qubits import default_qubits @@ -37,7 +36,7 @@ def __init__(self, num_qubits, params, label="amplitudes", pershot=False, condit [Default: False]. Raises: - ExtensionError: if params is invalid for the specified number of qubits. + ValueError: if params is invalid for the specified number of qubits. """ params = _format_amplitude_params(params, num_qubits) super().__init__( @@ -78,7 +77,7 @@ def __init__( [Default: False]. Raises: - ExtensionError: if params is invalid for the specified number of qubits. + ValueError: if params is invalid for the specified number of qubits. """ params = _format_amplitude_params(params, num_qubits) super().__init__( @@ -109,7 +108,7 @@ def save_amplitudes(self, params, label="amplitudes", pershot=False, conditional QuantumCircuit: with attached instruction. Raises: - ExtensionError: if params is invalid for the specified number of qubits. + ValueError: if params is invalid for the specified number of qubits. """ qubits = default_qubits(self) instr = SaveAmplitudes( @@ -139,7 +138,7 @@ def save_amplitudes_squared( QuantumCircuit: with attached instruction. Raises: - ExtensionError: if params is invalid for the specified number of qubits. + ValueError: if params is invalid for the specified number of qubits. """ qubits = default_qubits(self) instr = SaveAmplitudesSquared( @@ -161,7 +160,7 @@ def _format_amplitude_params(params, num_qubits=None): else: params = [int(i, 2) for i in params] if num_qubits and max(params) >= 2**num_qubits: - raise ExtensionError("Param values contain a state larger than the number of qubits") + raise ValueError("Param values contain a state larger than the number of qubits") return params diff --git a/qiskit_aer/library/save_instructions/save_data.py b/qiskit_aer/library/save_instructions/save_data.py index cb86edd94e..a98e88e12f 100644 --- a/qiskit_aer/library/save_instructions/save_data.py +++ b/qiskit_aer/library/save_instructions/save_data.py @@ -16,7 +16,6 @@ import copy from qiskit.circuit import Instruction -from qiskit.extensions.exceptions import ExtensionError class SaveData(Instruction): @@ -39,19 +38,17 @@ def __init__(self, name, num_qubits, label, subtype="single", params=None): [Default: None]. Raises: - ExtensionError: if the subtype string is invalid. + TypeError: if the subtype string is invalid. Additional Information: The supported subtypes are 'single', 'list', 'c_list', 'average', 'c_average', 'accum', 'c_accum'. """ if subtype not in self._allowed_subtypes: - raise ExtensionError("Invalid data subtype for SaveData instruction.") + raise TypeError("Invalid data subtype for SaveData instruction.") if not isinstance(label, str): - raise ExtensionError( - f"Invalid label for save data instruction, {label} must be a string." - ) + raise TypeError(f"Invalid label for save data instruction, {label} must be a string.") if params is None: params = {} diff --git a/qiskit_aer/library/save_instructions/save_expectation_value.py b/qiskit_aer/library/save_instructions/save_expectation_value.py index 27bcad9da0..c3e4f8f6ab 100644 --- a/qiskit_aer/library/save_instructions/save_expectation_value.py +++ b/qiskit_aer/library/save_instructions/save_expectation_value.py @@ -16,7 +16,6 @@ from numpy import allclose from qiskit.quantum_info import Pauli, SparsePauliOp, Operator from qiskit.circuit import QuantumCircuit -from qiskit.extensions.exceptions import ExtensionError from .save_data import SaveAverageData @@ -51,7 +50,8 @@ def __init__( values [Default: False]. Raises: - ExtensionError: if the input operator is invalid or not Hermitian. + ValueError: if the input operator is not Hermitian. + TypeError: if the input operator is of invalid type. .. note:: @@ -64,7 +64,7 @@ def __init__( elif not isinstance(operator, SparsePauliOp): operator = SparsePauliOp.from_operator(Operator(operator)) if not allclose(operator.coeffs.imag, 0): - raise ExtensionError("Input operator is not Hermitian.") + raise ValueError("Input operator is not Hermitian.") params = _expval_params(operator, variance=False) super().__init__( "save_expval", @@ -109,7 +109,8 @@ def __init__( values [Default: False]. Raises: - ExtensionError: if the input operator is invalid or not Hermitian. + ValueError: if the input operator is not Hermitian. + TypeError: if the input operator is of invalid type. .. note:: @@ -122,7 +123,7 @@ def __init__( elif not isinstance(operator, SparsePauliOp): operator = SparsePauliOp.from_operator(Operator(operator)) if not allclose(operator.coeffs.imag, 0): - raise ExtensionError("Input operator is not Hermitian.") + raise ValueError("Input operator is not Hermitian.") params = _expval_params(operator, variance=True) super().__init__( "save_expval_var", @@ -142,7 +143,7 @@ def _expval_params(operator, variance=False): elif not isinstance(operator, SparsePauliOp): operator = SparsePauliOp.from_operator(Operator(operator)) if not isinstance(operator, SparsePauliOp): - raise ExtensionError("Invalid input operator") + raise TypeError("Invalid input operator") params = {} @@ -196,7 +197,8 @@ def save_expectation_value( QuantumCircuit: with attached instruction. Raises: - ExtensionError: if the input operator is invalid or not Hermitian. + ValueError: if the input operator is not Hermitian. + TypeError: if the input operator is of invalid type. .. note:: @@ -237,7 +239,8 @@ def save_expectation_value_variance( QuantumCircuit: with attached instruction. Raises: - ExtensionError: if the input operator is invalid or not Hermitian. + ValueError: if the input operator is not Hermitian. + TypeError: if the input operator is of invalid type. .. note:: diff --git a/qiskit_aer/library/set_instructions/set_density_matrix.py b/qiskit_aer/library/set_instructions/set_density_matrix.py index 08b013e1aa..eb3afbf68d 100644 --- a/qiskit_aer/library/set_instructions/set_density_matrix.py +++ b/qiskit_aer/library/set_instructions/set_density_matrix.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info import DensityMatrix from ..default_qubits import default_qubits @@ -31,7 +30,7 @@ def __init__(self, state): state (DensityMatrix): a density matrix. Raises: - ExtensionError: if the input density matrix is not valid. + ValueError: if the input density matrix is not valid. .. note:: @@ -42,7 +41,7 @@ def __init__(self, state): if not isinstance(state, DensityMatrix): state = DensityMatrix(state) if not state.num_qubits or not state.is_valid(): - raise ExtensionError("The input state is not valid") + raise ValueError("The input state is not valid") super().__init__("set_density_matrix", state.num_qubits, 0, [state.data]) @@ -56,8 +55,8 @@ def set_density_matrix(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the density matrix is the incorrect size for the - current circuit. + ValueError: If the density matrix is the incorrect size for the + current circuit. .. note: @@ -67,7 +66,7 @@ def set_density_matrix(self, state): if not isinstance(state, DensityMatrix): state = DensityMatrix(state) if not state.num_qubits or state.num_qubits != len(qubits): - raise ExtensionError( + raise ValueError( "The size of the density matrix for the set state" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" diff --git a/qiskit_aer/library/set_instructions/set_matrix_product_state.py b/qiskit_aer/library/set_instructions/set_matrix_product_state.py index 1546c842f1..fcd50e0dd3 100644 --- a/qiskit_aer/library/set_instructions/set_matrix_product_state.py +++ b/qiskit_aer/library/set_instructions/set_matrix_product_state.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from ..default_qubits import default_qubits @@ -52,7 +51,7 @@ def set_matrix_product_state(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the structure of the state is incorrect + ValueError: If the structure of the state is incorrect .. note: @@ -60,21 +59,21 @@ def set_matrix_product_state(self, state): """ qubits = default_qubits(self) if not isinstance(state, tuple) or len(state) != 2: - raise ExtensionError( + raise ValueError( "The input matrix product state is not valid. Should be a list of 2 elements" ) if not isinstance(state[0], list) or not isinstance(state[1], list): - raise ExtensionError( + raise ValueError( "The first element of the input matrix product state is not valid. Should be a list." ) if len(state[0]) != len(state[1]) + 1: - raise ExtensionError( + raise ValueError( "The input matrix product state is not valid. " "Length of q_reg vector should be 1 more than length of lambda_reg" ) for elem in state[0]: if not isinstance(elem, tuple) or len(elem) != 2: - raise ExtensionError( + raise ValueError( "The input matrix product state is not valid." "The first element should be a list of length 2" ) diff --git a/qiskit_aer/library/set_instructions/set_stabilizer.py b/qiskit_aer/library/set_instructions/set_stabilizer.py index 7767560f41..60400f4586 100644 --- a/qiskit_aer/library/set_instructions/set_stabilizer.py +++ b/qiskit_aer/library/set_instructions/set_stabilizer.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info import StabilizerState, Clifford from ..default_qubits import default_qubits @@ -53,8 +52,8 @@ def set_stabilizer(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the state is the incorrect size for the - current circuit. + ValueError: If the state is the incorrect size for the + current circuit. .. note: @@ -66,7 +65,7 @@ def set_stabilizer(self, state): if not isinstance(state, Clifford): state = Clifford(state) if state.num_qubits != len(qubits): - raise ExtensionError( + raise ValueError( "The size of the Clifford for the set_stabilizer" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" diff --git a/qiskit_aer/library/set_instructions/set_statevector.py b/qiskit_aer/library/set_instructions/set_statevector.py index 25603cecc5..25671d5e39 100644 --- a/qiskit_aer/library/set_instructions/set_statevector.py +++ b/qiskit_aer/library/set_instructions/set_statevector.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info import Statevector from ..default_qubits import default_qubits @@ -31,7 +30,7 @@ def __init__(self, state): state (Statevector): a statevector. Raises: - ExtensionError: if the input is not a valid state. + ValueError: if the input is not a valid state. .. note:: @@ -42,7 +41,7 @@ def __init__(self, state): if not isinstance(state, Statevector): state = Statevector(state) if not state.num_qubits or not state.is_valid(): - raise ExtensionError("The input statevector is not valid") + raise ValueError("The input statevector is not valid") super().__init__("set_statevector", state.num_qubits, 0, [state.data]) @@ -56,8 +55,8 @@ def set_statevector(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the state is the incorrect size for the - current circuit. + ValueError: If the state is the incorrect size for the + current circuit. .. note: @@ -67,7 +66,7 @@ def set_statevector(self, state): if not isinstance(state, Statevector): state = Statevector(state) if not state.num_qubits or state.num_qubits != len(qubits): - raise ExtensionError( + raise ValueError( "The size of the statevector for the set_statevector" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" diff --git a/qiskit_aer/library/set_instructions/set_superop.py b/qiskit_aer/library/set_instructions/set_superop.py index 0538e5f2dd..f7e26066d4 100644 --- a/qiskit_aer/library/set_instructions/set_superop.py +++ b/qiskit_aer/library/set_instructions/set_superop.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info import SuperOp from ..default_qubits import default_qubits @@ -31,7 +30,7 @@ def __init__(self, state): state (QuantumChannel): A CPTP quantum channel. Raises: - ExtensionError: if the input QuantumChannel is not CPTP. + ValueError: if the input QuantumChannel is not CPTP. .. note:: @@ -42,7 +41,7 @@ def __init__(self, state): if not isinstance(state, SuperOp): state = SuperOp(state) if not state.num_qubits or not state.is_cptp(): - raise ExtensionError("The input quantum channel is not CPTP") + raise ValueError("The input quantum channel is not CPTP") super().__init__("set_superop", state.num_qubits, 0, [state.data]) @@ -56,9 +55,8 @@ def set_superop(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the state is the incorrect size for the - current circuit. - ExtensionError: if the input QuantumChannel is not CPTP. + ValueError: If the state is the incorrect size for the current circuit. + ValueError: if the input QuantumChannel is not CPTP. .. note: @@ -68,7 +66,7 @@ def set_superop(self, state): if not isinstance(state, SuperOp): state = SuperOp(state) if not state.num_qubits or state.num_qubits != len(qubits): - raise ExtensionError( + raise ValueError( "The size of the quantum channel for the set_superop" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" diff --git a/qiskit_aer/library/set_instructions/set_unitary.py b/qiskit_aer/library/set_instructions/set_unitary.py index ab8e261cdc..9c0fa785e6 100644 --- a/qiskit_aer/library/set_instructions/set_unitary.py +++ b/qiskit_aer/library/set_instructions/set_unitary.py @@ -14,7 +14,6 @@ """ from qiskit.circuit import QuantumCircuit, Instruction -from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info import Operator from ..default_qubits import default_qubits @@ -31,7 +30,7 @@ def __init__(self, state): state (Operator): A unitary matrix. Raises: - ExtensionError: if the input matrix is not state. + ValueError: if the input matrix is not state. .. note:: @@ -42,7 +41,7 @@ def __init__(self, state): if not isinstance(state, Operator): state = Operator(state) if not state.num_qubits or not state.is_unitary(): - raise ExtensionError("The input matrix is not unitary") + raise ValueError("The input matrix is not unitary") super().__init__("set_unitary", state.num_qubits, 0, [state.data]) @@ -56,9 +55,8 @@ def set_unitary(self, state): QuantumCircuit: with attached instruction. Raises: - ExtensionError: If the state is the incorrect size for the - current circuit. - ExtensionError: if the input matrix is not unitary. + ValueError: If the state is the incorrect size for the current circuit. + ValueError: if the input matrix is not unitary. .. note: @@ -68,7 +66,7 @@ def set_unitary(self, state): if not isinstance(state, Operator): state = Operator(state) if not state.num_qubits or state.num_qubits != len(qubits): - raise ExtensionError( + raise ValueError( "The size of the unitary matrix for the set_unitary" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" diff --git a/qiskit_aer/noise/errors/quantum_error.py b/qiskit_aer/noise/errors/quantum_error.py index 0846467eeb..3989a5020d 100644 --- a/qiskit_aer/noise/errors/quantum_error.py +++ b/qiskit_aer/noise/errors/quantum_error.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Quantum error class for Qiskit Aer noise model +Quantum error class for Aer noise model """ import copy import numbers @@ -21,7 +21,7 @@ from qiskit.circuit import QuantumCircuit, Instruction, QuantumRegister, Reset from qiskit.circuit.exceptions import CircuitError -from qiskit.circuit.library.generalized_gates import PauliGate +from qiskit.circuit.library.generalized_gates import PauliGate, UnitaryGate from qiskit.circuit.library.standard_gates import IGate, XGate, YGate, ZGate from qiskit.exceptions import QiskitError from qiskit.quantum_info.operators.base_operator import BaseOperator @@ -30,13 +30,12 @@ from qiskit.quantum_info.operators.mixins import TolerancesMixin from qiskit.quantum_info.operators.predicates import is_identity_matrix from qiskit.quantum_info.operators.symplectic import Clifford -from qiskit.extensions import UnitaryGate from ..noiseerror import NoiseError class QuantumError(BaseOperator, TolerancesMixin): """ - Quantum error class for Qiskit Aer noise model + Quantum error class for Aer noise model .. warning:: The init interface for this class is not finalized and may diff --git a/qiskit_aer/noise/errors/readout_error.py b/qiskit_aer/noise/errors/readout_error.py index 8374e6736c..ef37dcbfc4 100644 --- a/qiskit_aer/noise/errors/readout_error.py +++ b/qiskit_aer/noise/errors/readout_error.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Readout error class for Qiskit Aer noise model. +Readout error class for Aer noise model. """ import copy @@ -25,7 +25,7 @@ class ReadoutError: """ - Readout error class for Qiskit Aer noise model. + Readout error class for Aer noise model. """ # pylint: disable=invalid-name @@ -348,3 +348,8 @@ def __sub__(self, other): def __neg__(self): raise NotImplementedError("'ReadoutError' does not support negation.") + + @property + def num_qubits(self): + """Return the number of qubits.""" + return self._number_of_qubits diff --git a/qiskit_aer/noise/errors/standard_errors.py b/qiskit_aer/noise/errors/standard_errors.py index c9d85eddf4..69b182f280 100644 --- a/qiskit_aer/noise/errors/standard_errors.py +++ b/qiskit_aer/noise/errors/standard_errors.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Standard quantum computing error channels for Qiskit Aer. +Standard quantum computing error channels for Aer. """ import itertools as it @@ -19,8 +19,8 @@ from qiskit.circuit import Reset from qiskit.circuit.library.standard_gates import IGate, XGate, ZGate +from qiskit.circuit.library.generalized_gates import UnitaryGate from qiskit.exceptions import QiskitError -from qiskit.extensions import UnitaryGate from qiskit.quantum_info.operators import Pauli from qiskit.quantum_info.operators.channel import Choi, Kraus from qiskit.quantum_info.operators.predicates import is_identity_matrix diff --git a/qiskit_aer/noise/noise_model.py b/qiskit_aer/noise/noise_model.py index a32fcc2020..1223b0b8ea 100644 --- a/qiskit_aer/noise/noise_model.py +++ b/qiskit_aer/noise/noise_model.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """ -Noise model class for Qiskit Aer simulators. +Noise model class for Aer simulators. """ import copy import json @@ -23,8 +23,7 @@ from qiskit.circuit import Instruction, Delay from qiskit.circuit import QuantumCircuit from qiskit.circuit import Reset -from qiskit.circuit.library.generalized_gates import PauliGate -from qiskit.extensions import UnitaryGate +from qiskit.circuit.library.generalized_gates import PauliGate, UnitaryGate from qiskit.providers import QubitProperties from qiskit.providers.exceptions import BackendPropertyError from qiskit.providers.models import BackendProperties @@ -78,7 +77,7 @@ def __init__(self, qerror): class NoiseModel: - """Noise model class for Qiskit Aer simulators. + """Noise model class for Aer simulators. This class is used to represent noise model for the :class:`~qiskit_aer.QasmSimulator`. It can be used to construct diff --git a/qiskit_aer/noise/noiseerror.py b/qiskit_aer/noise/noiseerror.py index cc3e5244c6..291d6fa33b 100644 --- a/qiskit_aer/noise/noiseerror.py +++ b/qiskit_aer/noise/noiseerror.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. """ -Exception for errors raised by Qiskit Aer noise module. +Exception for errors raised by Aer noise module. """ from qiskit import QiskitError diff --git a/qiskit_aer/primitives/estimator.py b/qiskit_aer/primitives/estimator.py index 65d87231c5..a337567ea4 100644 --- a/qiskit_aer/primitives/estimator.py +++ b/qiskit_aer/primitives/estimator.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2022. +# (C) Copyright IBM 2022, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -18,13 +18,11 @@ from collections import defaultdict from collections.abc import Sequence -from copy import copy from warnings import warn import numpy as np from qiskit.circuit import ParameterExpression, QuantumCircuit from qiskit.compiler import transpile -from qiskit.opflow import PauliSumOp from qiskit.primitives import BaseEstimator, EstimatorResult from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.primitives.utils import _circuit_key, _observable_key, init_observable @@ -32,6 +30,15 @@ from qiskit.quantum_info import Pauli, PauliList from qiskit.quantum_info.operators.base_operator import BaseOperator from qiskit.result.models import ExperimentResult +from qiskit.transpiler import CouplingMap, PassManager +from qiskit.transpiler.passes import ( + ApplyLayout, + EnlargeWithAncilla, + FullAncillaAllocation, + Optimize1qGatesDecomposition, + SetLayout, +) +from qiskit.utils import deprecate_func from .. import AerError, AerSimulator @@ -84,7 +91,7 @@ def __init__( transpile_options: Options passed to transpile. run_options: Options passed to run. approximation: If True, it calculates expectation values with normal distribution - approximation. + approximation. Note that this appproximation ignores readout errors. skip_transpilation: If True, transpilation is skipped. abelian_grouping: Whether the observable should be grouped into commuting. If approximation is True, this parameter is ignored and assumed to be False. @@ -100,7 +107,15 @@ def __init__( self._transpile_options = Options() if transpile_options is not None: self._transpile_options.update_options(**transpile_options) - self.approximation = approximation + if not approximation: + warn( + "Option approximation=False is deprecated as of qiskit-aer 0.13. " + "It will be removed no earlier than 3 months after the release date. " + "Instead, use BackendEstimator from qiskit.primitives.", + DeprecationWarning, + stacklevel=3, + ) + self._approximation = approximation self._skip_transpilation = skip_transpilation self._cache: dict[tuple[tuple[int], tuple[int], bool], tuple[dict, dict]] = {} self._transpiled_circuits: dict[int, QuantumCircuit] = {} @@ -109,6 +124,34 @@ def __init__( self._observable_ids: dict[tuple, int] = {} self._abelian_grouping = abelian_grouping + @property + @deprecate_func( + since="0.13", + package_name="qiskit-aer", + is_property=True, + ) + def approximation(self): + """The approximation property""" + return self._approximation + + @approximation.setter + @deprecate_func( + since="0.13", + package_name="qiskit-aer", + is_property=True, + ) + def approximation(self, approximation): + """Setter for approximation""" + if not approximation: + warn( + "Option approximation=False is deprecated as of qiskit-aer 0.13. " + "It will be removed no earlier than 3 months after the release date. " + "Instead, use BackendEstimator from qiskit.primitives.", + DeprecationWarning, + stacklevel=3, + ) + self._approximation = approximation + def _call( self, circuits: Sequence[int], @@ -120,7 +163,7 @@ def _call( if seed is not None: run_options.setdefault("seed_simulator", seed) - if self.approximation: + if self._approximation: return self._compute_with_approximation( circuits, observables, parameter_values, run_options, seed ) @@ -130,7 +173,7 @@ def _call( def _run( self, circuits: Sequence[QuantumCircuit], - observables: Sequence[BaseOperator | PauliSumOp], + observables: Sequence[BaseOperator], parameter_values: Sequence[Sequence[float]], **run_options, ) -> PrimitiveJob: @@ -174,7 +217,7 @@ def _compute(self, circuits, observables, parameter_values, run_options): ) # Key for cache - key = (tuple(circuits), tuple(observables), self.approximation) + key = (tuple(circuits), tuple(observables), self._approximation) # Create expectation value experiments. if key in self._cache: # Use a cache @@ -297,11 +340,20 @@ def _create_meas_circuit(self, basis: Pauli, circuit_index: int): meas_circuit.h(qarg) meas_circuit.measure(qarg, clbit) meas_circuit.metadata = {"basis": basis} + if self._skip_transpilation: return meas_circuit - transpile_opts = copy(self._transpile_options) - transpile_opts.update_options(initial_layout=self._layouts[circuit_index]) - return transpile(meas_circuit, self._backend, **transpile_opts.__dict__) + + layout = self._layouts[circuit_index] + passmanager = PassManager([SetLayout(layout)]) + opt1q = Optimize1qGatesDecomposition(target=self._backend.target) + passmanager.append(opt1q) + if isinstance(self._backend.coupling_map, CouplingMap): + coupling_map = self._backend.coupling_map + passmanager.append(FullAncillaAllocation(coupling_map)) + passmanager.append(EnlargeWithAncilla()) + passmanager.append(ApplyLayout()) + return passmanager.run(meas_circuit) @staticmethod def _combine_circs(circuit: QuantumCircuit, meas_circuits: list[QuantumCircuit]): @@ -363,7 +415,7 @@ def _compute_with_approximation( self, circuits, observables, parameter_values, run_options, seed ): # Key for cache - key = (tuple(circuits), tuple(observables), self.approximation) + key = (tuple(circuits), tuple(observables), self._approximation) shots = run_options.pop("shots", None) # Create expectation value experiments. diff --git a/qiskit_aer/quantum_info/states/aer_statevector.py b/qiskit_aer/quantum_info/states/aer_statevector.py index fa4acf321e..eac02af221 100644 --- a/qiskit_aer/quantum_info/states/aer_statevector.py +++ b/qiskit_aer/quantum_info/states/aer_statevector.py @@ -260,10 +260,10 @@ def _aer_evolve_instruction(aer_state, inst, qubits, basis_gates=None): pass else: applied = False - elif inst.name == "kraus": - aer_state.apply_kraus(qubits, inst.params) elif inst.name == "reset": aer_state.apply_reset(qubits) + elif inst.name == "kraus": + aer_state.apply_kraus(qubits, inst.params) elif inst.name == "barrier": pass else: diff --git a/releasenotes/notes/add-rocm-support-db991e3c2f2ca455.yaml b/releasenotes/notes/0.13/add-rocm-support-db991e3c2f2ca455.yaml similarity index 100% rename from releasenotes/notes/add-rocm-support-db991e3c2f2ca455.yaml rename to releasenotes/notes/0.13/add-rocm-support-db991e3c2f2ca455.yaml diff --git a/releasenotes/notes/add_executor-a03f2d23cf6f4ca9.yaml b/releasenotes/notes/0.13/add_executor-a03f2d23cf6f4ca9.yaml similarity index 100% rename from releasenotes/notes/add_executor-a03f2d23cf6f4ca9.yaml rename to releasenotes/notes/0.13/add_executor-a03f2d23cf6f4ca9.yaml diff --git a/releasenotes/notes/add_executor-ba4870f86ed5d8ec.yaml b/releasenotes/notes/0.13/add_executor-ba4870f86ed5d8ec.yaml similarity index 100% rename from releasenotes/notes/add_executor-ba4870f86ed5d8ec.yaml rename to releasenotes/notes/0.13/add_executor-ba4870f86ed5d8ec.yaml diff --git a/releasenotes/notes/aer-runtime-api-exposed-wrong-sx-op-dadae6cf0787e169.yaml b/releasenotes/notes/0.13/aer-runtime-api-exposed-wrong-sx-op-dadae6cf0787e169.yaml similarity index 100% rename from releasenotes/notes/aer-runtime-api-exposed-wrong-sx-op-dadae6cf0787e169.yaml rename to releasenotes/notes/0.13/aer-runtime-api-exposed-wrong-sx-op-dadae6cf0787e169.yaml diff --git a/releasenotes/notes/avoid_copy_of_config-7f7891864c1a1bd0.yaml b/releasenotes/notes/0.13/avoid_copy_of_config-7f7891864c1a1bd0.yaml similarity index 100% rename from releasenotes/notes/avoid_copy_of_config-7f7891864c1a1bd0.yaml rename to releasenotes/notes/0.13/avoid_copy_of_config-7f7891864c1a1bd0.yaml diff --git a/releasenotes/notes/avoid_kernel_crash_in_mac_from_blas_error-bd5b836a23f2e3ee.yaml b/releasenotes/notes/0.13/avoid_kernel_crash_in_mac_from_blas_error-bd5b836a23f2e3ee.yaml similarity index 100% rename from releasenotes/notes/avoid_kernel_crash_in_mac_from_blas_error-bd5b836a23f2e3ee.yaml rename to releasenotes/notes/0.13/avoid_kernel_crash_in_mac_from_blas_error-bd5b836a23f2e3ee.yaml diff --git a/releasenotes/notes/check_param_length-eb69cd92825bbca4.yaml b/releasenotes/notes/0.13/check_param_length-eb69cd92825bbca4.yaml similarity index 100% rename from releasenotes/notes/check_param_length-eb69cd92825bbca4.yaml rename to releasenotes/notes/0.13/check_param_length-eb69cd92825bbca4.yaml diff --git a/releasenotes/notes/check_parameter_binds_exist-9d52c665d5f94dde.yaml b/releasenotes/notes/0.13/check_parameter_binds_exist-9d52c665d5f94dde.yaml similarity index 100% rename from releasenotes/notes/check_parameter_binds_exist-9d52c665d5f94dde.yaml rename to releasenotes/notes/0.13/check_parameter_binds_exist-9d52c665d5f94dde.yaml diff --git a/releasenotes/notes/correct_measure_in_state_controller-a92692fd7083c476.yaml b/releasenotes/notes/0.13/correct_measure_in_state_controller-a92692fd7083c476.yaml similarity index 100% rename from releasenotes/notes/correct_measure_in_state_controller-a92692fd7083c476.yaml rename to releasenotes/notes/0.13/correct_measure_in_state_controller-a92692fd7083c476.yaml diff --git a/releasenotes/notes/defer-backend-gathering-773d0ed8092c24d9.yaml b/releasenotes/notes/0.13/defer-backend-gathering-773d0ed8092c24d9.yaml similarity index 100% rename from releasenotes/notes/defer-backend-gathering-773d0ed8092c24d9.yaml rename to releasenotes/notes/0.13/defer-backend-gathering-773d0ed8092c24d9.yaml diff --git a/releasenotes/notes/do_not_modify_metadata-60bb4b88707bd021.yaml b/releasenotes/notes/0.13/do_not_modify_metadata-60bb4b88707bd021.yaml similarity index 100% rename from releasenotes/notes/do_not_modify_metadata-60bb4b88707bd021.yaml rename to releasenotes/notes/0.13/do_not_modify_metadata-60bb4b88707bd021.yaml diff --git a/releasenotes/notes/enhancement_ecr_for_stabilizer_simulator-00110a1b39d35054.yaml b/releasenotes/notes/0.13/enhancement_ecr_for_stabilizer_simulator-00110a1b39d35054.yaml similarity index 100% rename from releasenotes/notes/enhancement_ecr_for_stabilizer_simulator-00110a1b39d35054.yaml rename to releasenotes/notes/0.13/enhancement_ecr_for_stabilizer_simulator-00110a1b39d35054.yaml diff --git a/releasenotes/notes/estimator-order-bug-a341d82075f47046.yaml b/releasenotes/notes/0.13/estimator-order-bug-a341d82075f47046.yaml similarity index 100% rename from releasenotes/notes/estimator-order-bug-a341d82075f47046.yaml rename to releasenotes/notes/0.13/estimator-order-bug-a341d82075f47046.yaml diff --git a/releasenotes/notes/estimator-performance-da83a59b9fd69086.yaml b/releasenotes/notes/0.13/estimator-performance-da83a59b9fd69086.yaml similarity index 100% rename from releasenotes/notes/estimator-performance-da83a59b9fd69086.yaml rename to releasenotes/notes/0.13/estimator-performance-da83a59b9fd69086.yaml diff --git a/releasenotes/notes/estimator-variance-type-2b04ff7bcd305920.yaml b/releasenotes/notes/0.13/estimator-variance-type-2b04ff7bcd305920.yaml similarity index 100% rename from releasenotes/notes/estimator-variance-type-2b04ff7bcd305920.yaml rename to releasenotes/notes/0.13/estimator-variance-type-2b04ff7bcd305920.yaml diff --git a/releasenotes/notes/fix-aer-vector-alignment-aace6e14342c002e.yaml b/releasenotes/notes/0.13/fix-aer-vector-alignment-aace6e14342c002e.yaml similarity index 100% rename from releasenotes/notes/fix-aer-vector-alignment-aace6e14342c002e.yaml rename to releasenotes/notes/0.13/fix-aer-vector-alignment-aace6e14342c002e.yaml diff --git a/releasenotes/notes/fix-compiling-issue-in-release-with-vc++-47500a37841cfaa8.yaml b/releasenotes/notes/0.13/fix-compiling-issue-in-release-with-vc++-47500a37841cfaa8.yaml similarity index 100% rename from releasenotes/notes/fix-compiling-issue-in-release-with-vc++-47500a37841cfaa8.yaml rename to releasenotes/notes/0.13/fix-compiling-issue-in-release-with-vc++-47500a37841cfaa8.yaml diff --git a/releasenotes/notes/fix-cuStateVec_enable-0936f2269466e3be.yaml b/releasenotes/notes/0.13/fix-cuStateVec_enable-0936f2269466e3be.yaml similarity index 100% rename from releasenotes/notes/fix-cuStateVec_enable-0936f2269466e3be.yaml rename to releasenotes/notes/0.13/fix-cuStateVec_enable-0936f2269466e3be.yaml diff --git a/releasenotes/notes/fix-excitation-population-6af281a61f659dda.yaml b/releasenotes/notes/0.13/fix-excitation-population-6af281a61f659dda.yaml similarity index 100% rename from releasenotes/notes/fix-excitation-population-6af281a61f659dda.yaml rename to releasenotes/notes/0.13/fix-excitation-population-6af281a61f659dda.yaml diff --git a/releasenotes/notes/fix-none-handling-in-noise-model-34fcc9a3e3cbdf6f.yaml b/releasenotes/notes/0.13/fix-none-handling-in-noise-model-34fcc9a3e3cbdf6f.yaml similarity index 100% rename from releasenotes/notes/fix-none-handling-in-noise-model-34fcc9a3e3cbdf6f.yaml rename to releasenotes/notes/0.13/fix-none-handling-in-noise-model-34fcc9a3e3cbdf6f.yaml diff --git a/releasenotes/notes/fix-none-t2-handling-in-noise-model-5b712adf3569eccd.yaml b/releasenotes/notes/0.13/fix-none-t2-handling-in-noise-model-5b712adf3569eccd.yaml similarity index 100% rename from releasenotes/notes/fix-none-t2-handling-in-noise-model-5b712adf3569eccd.yaml rename to releasenotes/notes/0.13/fix-none-t2-handling-in-noise-model-5b712adf3569eccd.yaml diff --git a/releasenotes/notes/fix-number-qubits-a417ca6afa64264f.yaml b/releasenotes/notes/0.13/fix-number-qubits-a417ca6afa64264f.yaml similarity index 100% rename from releasenotes/notes/fix-number-qubits-a417ca6afa64264f.yaml rename to releasenotes/notes/0.13/fix-number-qubits-a417ca6afa64264f.yaml diff --git a/releasenotes/notes/fix_aer_state_initialize_api-0c2c237a606648ef.yaml b/releasenotes/notes/0.13/fix_aer_state_initialize_api-0c2c237a606648ef.yaml similarity index 100% rename from releasenotes/notes/fix_aer_state_initialize_api-0c2c237a606648ef.yaml rename to releasenotes/notes/0.13/fix_aer_state_initialize_api-0c2c237a606648ef.yaml diff --git a/releasenotes/notes/fix_cuQuantum_libpath-90d24880cd9a9ea8.yaml b/releasenotes/notes/0.13/fix_cuQuantum_libpath-90d24880cd9a9ea8.yaml similarity index 100% rename from releasenotes/notes/fix_cuQuantum_libpath-90d24880cd9a9ea8.yaml rename to releasenotes/notes/0.13/fix_cuQuantum_libpath-90d24880cd9a9ea8.yaml diff --git a/releasenotes/notes/fix_cuQuantum_static-ad132d742a64a3d5.yaml b/releasenotes/notes/0.13/fix_cuQuantum_static-ad132d742a64a3d5.yaml similarity index 100% rename from releasenotes/notes/fix_cuQuantum_static-ad132d742a64a3d5.yaml rename to releasenotes/notes/0.13/fix_cuQuantum_static-ad132d742a64a3d5.yaml diff --git a/releasenotes/notes/fix_gpu_binary-1b5b162dff76060d.yaml b/releasenotes/notes/0.13/fix_gpu_binary-1b5b162dff76060d.yaml similarity index 100% rename from releasenotes/notes/fix_gpu_binary-1b5b162dff76060d.yaml rename to releasenotes/notes/0.13/fix_gpu_binary-1b5b162dff76060d.yaml diff --git a/releasenotes/notes/fix_matplotlib_dependency-5b8ba26da6a98e3a.yaml b/releasenotes/notes/0.13/fix_matplotlib_dependency-5b8ba26da6a98e3a.yaml similarity index 100% rename from releasenotes/notes/fix_matplotlib_dependency-5b8ba26da6a98e3a.yaml rename to releasenotes/notes/0.13/fix_matplotlib_dependency-5b8ba26da6a98e3a.yaml diff --git a/releasenotes/notes/fix_mpi_procs-68b76c11fe7a6b8e.yaml b/releasenotes/notes/0.13/fix_mpi_procs-68b76c11fe7a6b8e.yaml similarity index 100% rename from releasenotes/notes/fix_mpi_procs-68b76c11fe7a6b8e.yaml rename to releasenotes/notes/0.13/fix_mpi_procs-68b76c11fe7a6b8e.yaml diff --git a/releasenotes/notes/fix_mps_extstabilizer_required_memory-f4fb0aebfeeb68e2.yaml b/releasenotes/notes/0.13/fix_mps_extstabilizer_required_memory-f4fb0aebfeeb68e2.yaml similarity index 100% rename from releasenotes/notes/fix_mps_extstabilizer_required_memory-f4fb0aebfeeb68e2.yaml rename to releasenotes/notes/0.13/fix_mps_extstabilizer_required_memory-f4fb0aebfeeb68e2.yaml diff --git a/releasenotes/notes/fix_omp_nested-a554de2e7fd2a2d6.yaml b/releasenotes/notes/0.13/fix_omp_nested-a554de2e7fd2a2d6.yaml similarity index 100% rename from releasenotes/notes/fix_omp_nested-a554de2e7fd2a2d6.yaml rename to releasenotes/notes/0.13/fix_omp_nested-a554de2e7fd2a2d6.yaml diff --git a/releasenotes/notes/fix_omp_nested_performance-a3d55f3e85366a5b.yaml b/releasenotes/notes/0.13/fix_omp_nested_performance-a3d55f3e85366a5b.yaml similarity index 100% rename from releasenotes/notes/fix_omp_nested_performance-a3d55f3e85366a5b.yaml rename to releasenotes/notes/0.13/fix_omp_nested_performance-a3d55f3e85366a5b.yaml diff --git a/releasenotes/notes/fix_param_binding_for_pram_circuit-50e64efbedaec8fd.yaml b/releasenotes/notes/0.13/fix_param_binding_for_pram_circuit-50e64efbedaec8fd.yaml similarity index 100% rename from releasenotes/notes/fix_param_binding_for_pram_circuit-50e64efbedaec8fd.yaml rename to releasenotes/notes/0.13/fix_param_binding_for_pram_circuit-50e64efbedaec8fd.yaml diff --git a/releasenotes/notes/fix_parameter_indexing-f29f19568270d002.yaml b/releasenotes/notes/0.13/fix_parameter_indexing-f29f19568270d002.yaml similarity index 100% rename from releasenotes/notes/fix_parameter_indexing-f29f19568270d002.yaml rename to releasenotes/notes/0.13/fix_parameter_indexing-f29f19568270d002.yaml diff --git a/releasenotes/notes/fix_qobj_run-8ea657a93ce9acd2.yaml b/releasenotes/notes/0.13/fix_qobj_run-8ea657a93ce9acd2.yaml similarity index 100% rename from releasenotes/notes/fix_qobj_run-8ea657a93ce9acd2.yaml rename to releasenotes/notes/0.13/fix_qobj_run-8ea657a93ce9acd2.yaml diff --git a/releasenotes/notes/fix_required_memory_mb-7aeafa0fe553b85a.yaml b/releasenotes/notes/0.13/fix_required_memory_mb-7aeafa0fe553b85a.yaml similarity index 100% rename from releasenotes/notes/fix_required_memory_mb-7aeafa0fe553b85a.yaml rename to releasenotes/notes/0.13/fix_required_memory_mb-7aeafa0fe553b85a.yaml diff --git a/releasenotes/notes/fix_stabilizer_measure-49f9b4261dfaa4d3.yaml b/releasenotes/notes/0.13/fix_stabilizer_measure-49f9b4261dfaa4d3.yaml similarity index 100% rename from releasenotes/notes/fix_stabilizer_measure-49f9b4261dfaa4d3.yaml rename to releasenotes/notes/0.13/fix_stabilizer_measure-49f9b4261dfaa4d3.yaml diff --git a/releasenotes/notes/implicit_cast_for_arguments-a3c671db2fff6f17.yaml b/releasenotes/notes/0.13/implicit_cast_for_arguments-a3c671db2fff6f17.yaml similarity index 100% rename from releasenotes/notes/implicit_cast_for_arguments-a3c671db2fff6f17.yaml rename to releasenotes/notes/0.13/implicit_cast_for_arguments-a3c671db2fff6f17.yaml diff --git a/releasenotes/notes/latest-vc++-compilation-fixes-555601315e7e821b.yaml b/releasenotes/notes/0.13/latest-vc++-compilation-fixes-555601315e7e821b.yaml similarity index 100% rename from releasenotes/notes/latest-vc++-compilation-fixes-555601315e7e821b.yaml rename to releasenotes/notes/0.13/latest-vc++-compilation-fixes-555601315e7e821b.yaml diff --git a/releasenotes/notes/primitives-grouping-index-bug-56f69afbdc3e86a0.yaml b/releasenotes/notes/0.13/primitives-grouping-index-bug-56f69afbdc3e86a0.yaml similarity index 100% rename from releasenotes/notes/primitives-grouping-index-bug-56f69afbdc3e86a0.yaml rename to releasenotes/notes/0.13/primitives-grouping-index-bug-56f69afbdc3e86a0.yaml diff --git a/releasenotes/notes/quantum_error_from_dict-8188a864109edd67.yaml b/releasenotes/notes/0.13/quantum_error_from_dict-8188a864109edd67.yaml similarity index 100% rename from releasenotes/notes/quantum_error_from_dict-8188a864109edd67.yaml rename to releasenotes/notes/0.13/quantum_error_from_dict-8188a864109edd67.yaml diff --git a/releasenotes/notes/0.13/release_0.13.0-456c0b054ea30a1b.yaml b/releasenotes/notes/0.13/release_0.13.0-456c0b054ea30a1b.yaml new file mode 100644 index 0000000000..702a966853 --- /dev/null +++ b/releasenotes/notes/0.13/release_0.13.0-456c0b054ea30a1b.yaml @@ -0,0 +1,22 @@ +--- +prelude: > + Here are highlights of the Aer 0.13.0 release: + + Aer's backend is now backendV2. + + Introducing shot-branching optimization that accelerates dynamic circuits + simulations. By using `shot_branching_enable=True`, multi-shots + simulation starts with single state and state will be branched with + attached shots dynamically. This option is available for `statevector`, + `density_matrix` and `tensor_network` methods. + + Adding support for classical expressions used for branch operations. + + Introducing runtime parameter binding that accelerates parameterized + circuits simulations on GPU. With `runtime_parameter_bind_enable=True` + and `batched_shots_gpu=True`, this optimization will be enabled on GPU. + This optimization can be used with Aer primitives. + + Fix dynamic link library path for GPU binary distributions. + + Now Aer supports AMD's GPUs based on ROCm (building from source code only) diff --git a/releasenotes/notes/remove_aer_circuit_from_metadata-e4fe09029c1a3a3c.yaml b/releasenotes/notes/0.13/remove_aer_circuit_from_metadata-e4fe09029c1a3a3c.yaml similarity index 100% rename from releasenotes/notes/remove_aer_circuit_from_metadata-e4fe09029c1a3a3c.yaml rename to releasenotes/notes/0.13/remove_aer_circuit_from_metadata-e4fe09029c1a3a3c.yaml diff --git a/releasenotes/notes/remove_pulse_simulator-f8de2f6d380f446a.yaml b/releasenotes/notes/0.13/remove_pulse_simulator-f8de2f6d380f446a.yaml similarity index 100% rename from releasenotes/notes/remove_pulse_simulator-f8de2f6d380f446a.yaml rename to releasenotes/notes/0.13/remove_pulse_simulator-f8de2f6d380f446a.yaml diff --git a/releasenotes/notes/renew_gpu_binaries-2cf3eba0853b8407.yaml b/releasenotes/notes/0.13/renew_gpu_binaries-2cf3eba0853b8407.yaml similarity index 100% rename from releasenotes/notes/renew_gpu_binaries-2cf3eba0853b8407.yaml rename to releasenotes/notes/0.13/renew_gpu_binaries-2cf3eba0853b8407.yaml diff --git a/releasenotes/notes/runtime_parameter_binding-d2c57255f02729a1.yaml b/releasenotes/notes/0.13/runtime_parameter_binding-d2c57255f02729a1.yaml similarity index 100% rename from releasenotes/notes/runtime_parameter_binding-d2c57255f02729a1.yaml rename to releasenotes/notes/0.13/runtime_parameter_binding-d2c57255f02729a1.yaml diff --git a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml b/releasenotes/notes/0.13/sampler-performance-81e1649ec4657aad.yaml similarity index 100% rename from releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml rename to releasenotes/notes/0.13/sampler-performance-81e1649ec4657aad.yaml diff --git a/releasenotes/notes/save_statevector_for_qasm3_circ-642ade99af3ff0d2.yaml b/releasenotes/notes/0.13/save_statevector_for_qasm3_circ-642ade99af3ff0d2.yaml similarity index 100% rename from releasenotes/notes/save_statevector_for_qasm3_circ-642ade99af3ff0d2.yaml rename to releasenotes/notes/0.13/save_statevector_for_qasm3_circ-642ade99af3ff0d2.yaml diff --git a/releasenotes/notes/skip-cuda-requirements-927ddce79b9e7108.yaml b/releasenotes/notes/0.13/skip-cuda-requirements-927ddce79b9e7108.yaml similarity index 100% rename from releasenotes/notes/skip-cuda-requirements-927ddce79b9e7108.yaml rename to releasenotes/notes/0.13/skip-cuda-requirements-927ddce79b9e7108.yaml diff --git a/releasenotes/notes/stabilizer_rotation-8ce2effd9578ee0a.yaml b/releasenotes/notes/0.13/stabilizer_rotation-8ce2effd9578ee0a.yaml similarity index 100% rename from releasenotes/notes/stabilizer_rotation-8ce2effd9578ee0a.yaml rename to releasenotes/notes/0.13/stabilizer_rotation-8ce2effd9578ee0a.yaml diff --git a/releasenotes/notes/0.13/support_backend_v2-9eeb4690199b01d1.yaml b/releasenotes/notes/0.13/support_backend_v2-9eeb4690199b01d1.yaml new file mode 100644 index 0000000000..2579d71794 --- /dev/null +++ b/releasenotes/notes/0.13/support_backend_v2-9eeb4690199b01d1.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Update Aer Backend to BackendV2. Refer to `#1681`. + BackendV2 is differs from BackendV1 in the following points: backend.name() changes to backend.name string attribute, + the configuration attribute no longer exists, and the options attribute is added. For more information about BackendV2 is + `here`. \ No newline at end of file diff --git a/releasenotes/notes/0.13/support_c_if_reset-1f0b8e84948fb3fc.yaml b/releasenotes/notes/0.13/support_c_if_reset-1f0b8e84948fb3fc.yaml new file mode 100644 index 0000000000..ea0d00edcd --- /dev/null +++ b/releasenotes/notes/0.13/support_c_if_reset-1f0b8e84948fb3fc.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + ``c_if`` is supportted of ``reset`` instruction and an exception + is thrown if `c_if` is called for an instruction that does not + support ``c_if``. diff --git a/releasenotes/notes/0.13/support_classical_expr-dd621e5c0fd23a15.yaml b/releasenotes/notes/0.13/support_classical_expr-dd621e5c0fd23a15.yaml new file mode 100644 index 0000000000..11269398cb --- /dev/null +++ b/releasenotes/notes/0.13/support_classical_expr-dd621e5c0fd23a15.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Support ``qiskit.circuit.classical.expr.Expr`` introduced in Qiskit 0.44. + If a circuit includes unsupported expression which will be introduced in Qiskit 0.45 + or later, ``AerError`` is thrown. Objects of sub-classes of ``Expr`` are converted to + corresponding sub-classes of ``AER::Operations::CExpr`` in C++ and evaluated. + In addition, ``AER::Operations::RegComparison`` in ``bfunc`` operation is replaced + with corresponding binary operations. + diff --git a/releasenotes/notes/support_int_initialize-8491979c4a003908.yaml b/releasenotes/notes/0.13/support_int_initialize-8491979c4a003908.yaml similarity index 100% rename from releasenotes/notes/support_int_initialize-8491979c4a003908.yaml rename to releasenotes/notes/0.13/support_int_initialize-8491979c4a003908.yaml diff --git a/releasenotes/notes/support_param_for_global_phase-704a97129e7bdbaa.yaml b/releasenotes/notes/0.13/support_param_for_global_phase-704a97129e7bdbaa.yaml similarity index 100% rename from releasenotes/notes/support_param_for_global_phase-704a97129e7bdbaa.yaml rename to releasenotes/notes/0.13/support_param_for_global_phase-704a97129e7bdbaa.yaml diff --git a/releasenotes/notes/support_switch-41603d87cb8358fb.yaml b/releasenotes/notes/0.13/support_switch-41603d87cb8358fb.yaml similarity index 100% rename from releasenotes/notes/support_switch-41603d87cb8358fb.yaml rename to releasenotes/notes/0.13/support_switch-41603d87cb8358fb.yaml diff --git a/releasenotes/notes/0.13/support_switch_transpilation-67e16241b94faa86.yaml b/releasenotes/notes/0.13/support_switch_transpilation-67e16241b94faa86.yaml new file mode 100644 index 0000000000..0704fbc314 --- /dev/null +++ b/releasenotes/notes/0.13/support_switch_transpilation-67e16241b94faa86.yaml @@ -0,0 +1,5 @@ +--- +issues: + - | + Though Aer supports ``switch`` for several methods, transpilation of circuits with ``switch`` has been failed. + This commit enables such transpilation by adding ``switch_case`` operations into basis gates. diff --git a/releasenotes/notes/support_u3_runtime_api-42f013f111c319ff.yaml b/releasenotes/notes/0.13/support_u3_runtime_api-42f013f111c319ff.yaml similarity index 100% rename from releasenotes/notes/support_u3_runtime_api-42f013f111c319ff.yaml rename to releasenotes/notes/0.13/support_u3_runtime_api-42f013f111c319ff.yaml diff --git a/releasenotes/notes/use_omp_set_max_active_levels-7e6c1d301c4434a6.yaml b/releasenotes/notes/0.13/use_omp_set_max_active_levels-7e6c1d301c4434a6.yaml similarity index 100% rename from releasenotes/notes/use_omp_set_max_active_levels-7e6c1d301c4434a6.yaml rename to releasenotes/notes/0.13/use_omp_set_max_active_levels-7e6c1d301c4434a6.yaml diff --git a/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml b/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml new file mode 100644 index 0000000000..f2cf556195 --- /dev/null +++ b/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml @@ -0,0 +1,13 @@ +--- +fixes: + - | + Fixes AerBackend issues caused by upgading to BackendV2 in 0.13.0 release + and fix test failures for Qiskit 0.45 release. + + For issue #1987, added description if backend given by from_backend does not + have description. + + For issue #1988, added building coupling map from option. + + For issue #1982, added custome pass maneger to rebuild basis gates from + input circuits to prevent unnecessary gate changes diff --git a/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml new file mode 100644 index 0000000000..92c8c46c03 --- /dev/null +++ b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed `stabilizer` was selected with `method="automatic" ` when simulating + circuits with rotational gates with noise models for small number of qubits + even it is faster to calculate with `density_matrix` method. + This fix checks if `density_matrix` method with noise model is faster or not + at first and then check using `stabilizer` method. + This is side effect of implementing rotational gates in stabilizer PR #1938 diff --git a/releasenotes/notes/fix_basis_gates-5edf9708e3eec097.yaml b/releasenotes/notes/fix_basis_gates-5edf9708e3eec097.yaml new file mode 100644 index 0000000000..6fa974b2e8 --- /dev/null +++ b/releasenotes/notes/fix_basis_gates-5edf9708e3eec097.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed basis gates sets of Aer backend, moved `reset` and `switch_case` + to custom instructions. diff --git a/releasenotes/notes/fix_batch_shots-837c066d8b993a2d.yaml b/releasenotes/notes/fix_batch_shots-837c066d8b993a2d.yaml new file mode 100644 index 0000000000..3e3ef26134 --- /dev/null +++ b/releasenotes/notes/fix_batch_shots-837c066d8b993a2d.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed GPU batched shots optimization and GPU runtime parameter binding + failures caused by wrong checking of return condition diff --git a/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml b/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml new file mode 100644 index 0000000000..2551b8bc47 --- /dev/null +++ b/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml @@ -0,0 +1,6 @@ +fixes: + - | + Extended stabilizer simulation was sharing a single copy of RngEngine amongst + parallelized states in ``ExtendedStabilizer::State::apply_ops_parallel``, + leading to thread safety issue. Now, a new RngEngine is seeded for each parallel + state. \ No newline at end of file diff --git a/releasenotes/notes/fix_initialize_with_global_phase-56d529cd9c09c2fa.yaml b/releasenotes/notes/fix_initialize_with_global_phase-56d529cd9c09c2fa.yaml new file mode 100644 index 0000000000..565a5a0174 --- /dev/null +++ b/releasenotes/notes/fix_initialize_with_global_phase-56d529cd9c09c2fa.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + When applying `initialize`, global phase was not multiplied to state. + This fix multiplies global phase to `initialize` operation. + Also this fix applies global phase to `matrix_product_state` method, + which did not use global phase. diff --git a/releasenotes/notes/fix_sample_measure_roerr-747b955aa2bf778c.yaml b/releasenotes/notes/fix_sample_measure_roerr-747b955aa2bf778c.yaml new file mode 100644 index 0000000000..a36e891c3d --- /dev/null +++ b/releasenotes/notes/fix_sample_measure_roerr-747b955aa2bf778c.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes order of applying read out error in sampling measure + in circuit executors. Ordering is reversed to fit to the older verison + of Aer. + Also fixed check of bacth execution. diff --git a/releasenotes/notes/fix_simulator_init_gpu-597afb3d5241ed66.yaml b/releasenotes/notes/fix_simulator_init_gpu-597afb3d5241ed66.yaml new file mode 100644 index 0000000000..de2340b854 --- /dev/null +++ b/releasenotes/notes/fix_simulator_init_gpu-597afb3d5241ed66.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + This fix changes `device` query method from running simple circuit to + search devices from C++ binary to prevent initializing GPUs at + initialization phase and simulation methods are listed in Python code. + Aer built with GPU support will not initialize when `device=CPU` is used. + And only initialize and access GPUs defined in `target_gpus` option. diff --git a/releasenotes/notes/fix_stabilizer_ry_gate-07538d8a2462c09d.yaml b/releasenotes/notes/fix_stabilizer_ry_gate-07538d8a2462c09d.yaml new file mode 100644 index 0000000000..66c10e1191 --- /dev/null +++ b/releasenotes/notes/fix_stabilizer_ry_gate-07538d8a2462c09d.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + fixed ry gate for stabilizer method, PI/2 and PI3/2 was inverted diff --git a/releasenotes/notes/fix_transpiler_lvl_for_dynamic_circuit-4ead3b497bbcc632.yaml b/releasenotes/notes/fix_transpiler_lvl_for_dynamic_circuit-4ead3b497bbcc632.yaml new file mode 100644 index 0000000000..e42a2b33c1 --- /dev/null +++ b/releasenotes/notes/fix_transpiler_lvl_for_dynamic_circuit-4ead3b497bbcc632.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + For dynamic circuits, aer_compiler calls transpiler without optimizaiton + level. Because id gates are removed by transpiler, noise applied id gates + did not work correctly. This fix adds optimization_level=0 not to remove + id gates of dynamic circuits diff --git a/releasenotes/notes/psutil-added-ffb2a4b5956fa03d.yaml b/releasenotes/notes/psutil-added-ffb2a4b5956fa03d.yaml new file mode 100644 index 0000000000..34939eafd2 --- /dev/null +++ b/releasenotes/notes/psutil-added-ffb2a4b5956fa03d.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - | + Added `psutil `__ as a dependency for + Qiskit Aer. This is used to determine the amount of physical resources + available. ``psutil`` is currently a dependency of Qiskit, which is a + requirement for Qiskit Aer, so ``psutil`` was effectively already required + for any ``qiskit-aer`` installation. But, as qiskit-aer is now using it + directly is now a direct dependency for ``qiskit-aer``. diff --git a/releasenotes/notes/remove-opflow-estimator-a3b64cfe8a4fd6b3.yaml b/releasenotes/notes/remove-opflow-estimator-a3b64cfe8a4fd6b3.yaml new file mode 100644 index 0000000000..f79a41724c --- /dev/null +++ b/releasenotes/notes/remove-opflow-estimator-a3b64cfe8a4fd6b3.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + The :meth:`qiskit_aer.primitives.Estimator.run` method no longer supports + ``observables`` input arguments of type ``PauliSumOp``. The ``PauliSumOp`` + class was deprecated in Qiskit 0.44 and will be removed in Qiskit 1.0. + Alternative types that you can use instead of ``PauliSumOp`` are + :class:`qiskit.quantum_info.SparsePauliOp` or :class:`qiskit.quantum_info.Pauli`. diff --git a/releasenotes/notes/remove_qiskit_test-777882fa1591b6e7.yaml b/releasenotes/notes/remove_qiskit_test-777882fa1591b6e7.yaml new file mode 100644 index 0000000000..a66f7d10d6 --- /dev/null +++ b/releasenotes/notes/remove_qiskit_test-777882fa1591b6e7.yaml @@ -0,0 +1,4 @@ +--- +deprecations: + - | + Removed importing qiskit.test from test and include some classes in Aer diff --git a/releasenotes/notes/windows-blas-42b3dbc170c5ae94.yaml b/releasenotes/notes/windows-blas-42b3dbc170c5ae94.yaml new file mode 100644 index 0000000000..2a17a5544f --- /dev/null +++ b/releasenotes/notes/windows-blas-42b3dbc170c5ae94.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added CMake option ``USE_BUNDLED_BLAS_WIN`` which allows CMake to search + for a BLAS library against which to link instead of using the OpenBLAS + library bundled into the repo. diff --git a/requirements-dev.txt b/requirements-dev.txt index d1a45eda8b..8bde4bcb81 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -13,7 +13,7 @@ reno>=3.4.0 ddt>=1.2.0,!=1.4.0 matplotlib>=3.3 seaborn>=0.9.0 -qiskit_sphinx_theme~=1.12.0 +qiskit_sphinx_theme~=1.16.0 sphinx-design>=0.2.0 nbsphinx qiskit_qasm3_import diff --git a/setup.py b/setup.py index ea37a0c857..4ac0c20e17 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,10 @@ extras_requirements = {"dask": ["dask", "distributed"]} requirements = [ - "qiskit-terra>=0.21.0", + "qiskit>=0.45.0", "numpy>=1.16.3", "scipy>=1.0", + "psutil>=5", ] classifiers = [ @@ -64,6 +65,7 @@ else: requirements_cuda = [ "nvidia-cuda-runtime-cu12>=12.1.105", + "nvidia-nvjitlink-cu12", "nvidia-cublas-cu12>=12.1.3.1", "nvidia-cusolver-cu12>=11.4.5.107", "nvidia-cusparse-cu12>=12.1.0.106", @@ -89,12 +91,13 @@ if is_win_32_bit: cmake_args.append("-DCMAKE_GENERATOR_PLATFORM=Win32") + setup( name=PACKAGE_NAME, version=VERSION, packages=setuptools.find_packages(exclude=["test*"]), cmake_source_dir=".", - description="Qiskit Aer - High performance simulators for Qiskit", + description="Aer - High performance simulators for Qiskit", long_description=README, long_description_content_type="text/markdown", url="https://github.com/Qiskit/qiskit-aer", @@ -108,6 +111,11 @@ package_data={"qiskit_aer": ["VERSION.txt"], "qiskit_aer.library": ["*.csv"]}, extras_require=extras_requirements, cmake_args=cmake_args, - keywords="qiskit aer simulator quantum addon backend", + keywords="qiskit, simulator, quantum computing, backend", zip_safe=False, + entry_points={ + "qiskit.transpiler.translation": [ + "aer_backend_plugin = qiskit_aer.backends.plugin.aer_backend_plugin:AerBackendPlugin", + ] + }, ) diff --git a/src/controllers/aer_controller.hpp b/src/controllers/aer_controller.hpp index d216b4ff9e..b714ca4c33 100755 --- a/src/controllers/aer_controller.hpp +++ b/src/controllers/aer_controller.hpp @@ -74,7 +74,7 @@ namespace AER { class Controller { public: - Controller() { clear_parallelization(); } + Controller() {} //----------------------------------------------------------------------- // Execute qobj @@ -96,8 +96,8 @@ class Controller { // config settings will be passed to the State and Data classes void set_config(const Config &config); - // Clear the current config - void clear_config(); + // return available devicess + std::vector available_devices(); protected: //----------------------------------------------------------------------- @@ -162,9 +162,6 @@ class Controller { // Parallelization Config //----------------------------------------------------------------------- - // Set OpenMP thread settings to default values - void clear_parallelization(); - // Set parallelization for experiments void set_parallelization_experiments(const reg_t &required_memory_list); @@ -175,18 +172,18 @@ class Controller { size_t get_gpu_memory_mb(); // The maximum number of threads to use for various levels of parallelization - int max_parallel_threads_; + int max_parallel_threads_ = 0; // Parameters for parallelization management in configuration - int max_parallel_experiments_; - size_t max_memory_mb_; - size_t max_gpu_memory_mb_; + int max_parallel_experiments_ = 1; + size_t max_memory_mb_ = 0; + size_t max_gpu_memory_mb_ = 0; // use explicit parallelization - bool explicit_parallelization_; + bool explicit_parallelization_ = false; // Parameters for parallelization management for experiments - int parallel_experiments_; + int parallel_experiments_ = 1; bool parallel_nested_ = false; @@ -197,6 +194,8 @@ class Controller { // runtime parameter binding bool runtime_parameter_bind_ = false; + + reg_t target_gpus_; // GPUs to be used }; //========================================================================= @@ -231,6 +230,8 @@ void Controller::set_config(const Config &config) { if (config.max_memory_mb.has_value()) max_memory_mb_ = config.max_memory_mb.value(); + else + max_memory_mb_ = get_system_memory_mb(); // for debugging if (config._parallel_experiments.has_value()) { @@ -307,7 +308,21 @@ void Controller::set_config(const Config &config) { cudaGetLastError(); throw std::runtime_error("No CUDA device available!"); } + if (config.target_gpus.has_value()) { + target_gpus_ = config.target_gpus.value(); + + if (nDev < target_gpus_.size()) { + throw std::invalid_argument( + "target_gpus has more GPUs than available."); + } + } else { + target_gpus_.resize(nDev); + for (int_t i = 0; i < nDev; i++) + target_gpus_[i] = i; + } sim_device_ = Device::GPU; + + max_gpu_memory_mb_ = get_gpu_memory_mb(); #endif } else { throw std::runtime_error(std::string("Invalid simulation device (\"") + @@ -338,27 +353,6 @@ void Controller::set_config(const Config &config) { runtime_parameter_bind_ = config.runtime_parameter_bind_enable.value(); } -void Controller::clear_config() { - clear_parallelization(); - method_ = Method::automatic; - sim_device_ = Device::CPU; - sim_precision_ = Precision::Double; -} - -void Controller::clear_parallelization() { - max_parallel_threads_ = 0; - max_parallel_experiments_ = 1; - - parallel_experiments_ = 1; - parallel_nested_ = false; - - num_process_per_experiment_ = 1; - - explicit_parallelization_ = false; - max_memory_mb_ = get_system_memory_mb(); - max_gpu_memory_mb_ = get_gpu_memory_mb(); -} - void Controller::set_parallelization_experiments( const reg_t &required_memory_mb_list) { @@ -420,14 +414,9 @@ size_t Controller::get_system_memory_mb() { size_t Controller::get_gpu_memory_mb() { size_t total_physical_memory = 0; #ifdef AER_THRUST_GPU - int iDev, nDev, j; - if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - cudaGetLastError(); - nDev = 0; - } - for (iDev = 0; iDev < nDev; iDev++) { + for (uint_t iDev = 0; iDev < target_gpus_.size(); iDev++) { size_t freeMem, totalMem; - cudaSetDevice(iDev); + cudaSetDevice(target_gpus_[iDev]); cudaMemGetInfo(&freeMem, &totalMem); total_physical_memory += totalMem; } @@ -444,6 +433,20 @@ size_t Controller::get_gpu_memory_mb() { return total_physical_memory >> 20; } +std::vector Controller::available_devices() { + std::vector ret; + + ret.push_back(std::string("CPU")); +#ifdef AER_THRUST_GPU + ret.push_back(std::string("GPU")); +#else +#ifdef AER_THRUST_CPU + ret.push_back(std::string("Thrust")); +#endif +#endif + return ret; +} + //------------------------------------------------------------------------- // Qobj execution //------------------------------------------------------------------------- @@ -512,7 +515,7 @@ Result Controller::execute(std::vector> &circuits, uint_t result_size; reg_t result_offset(circuits.size()); result_size = 0; - for (int_t i = 0; i < circuits.size(); i++) { + for (uint_t i = 0; i < circuits.size(); i++) { result_offset[i] = result_size; result_size += circuits[i]->num_bind_params; } @@ -529,11 +532,11 @@ Result Controller::execute(std::vector> &circuits, // set parallelization for experiments try { uint_t res_pos = 0; - for (int i = 0; i < circuits.size(); i++) { + for (uint_t i = 0; i < circuits.size(); i++) { executors[i] = make_circuit_executor(methods[i]); required_memory_mb_list[i] = executors[i]->required_memory_mb(config, *circuits[i], noise_model); - for (int j = 0; j < circuits[i]->num_bind_params; j++) { + for (uint_t j = 0; j < circuits[i]->num_bind_params; j++) { result.results[res_pos++].metadata.add(required_memory_mb_list[i], "required_memory_mb"); } @@ -585,9 +588,9 @@ Result Controller::execute(std::vector> &circuits, reg_t seeds(result_size); reg_t avg_seeds(result_size); int_t iseed = 0; - for (int_t i = 0; i < circuits.size(); i++) { + for (uint_t i = 0; i < circuits.size(); i++) { if (circuits[i]->num_bind_params > 1) { - for (int_t j = 0; i < circuits[i]->num_bind_params; i++) + for (uint_t j = 0; i < circuits[i]->num_bind_params; i++) seeds[iseed++] = circuits[i]->seed_for_params[j]; } else seeds[iseed++] = circuits[i]->seed; @@ -595,9 +598,9 @@ Result Controller::execute(std::vector> &circuits, MPI_Allreduce(seeds.data(), avg_seeds.data(), result_size, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD); iseed = 0; - for (int_t i = 0; i < circuits.size(); i++) { + for (uint_t i = 0; i < circuits.size(); i++) { if (circuits[i]->num_bind_params > 1) { - for (int_t j = 0; i < circuits[i]->num_bind_params; i++) + for (uint_t j = 0; i < circuits[i]->num_bind_params; i++) circuits[i]->seed_for_params[j] = avg_seeds[iseed++] / num_processes_; } else @@ -623,7 +626,7 @@ Result Controller::execute(std::vector> &circuits, bool all_failed = true; result.status = Result::Status::completed; - for (int i = 0; i < result.results.size(); ++i) { + for (uint_t i = 0; i < result.results.size(); ++i) { auto &experiment = result.results[i]; if (experiment.status == ExperimentResult::Status::completed) { all_failed = false; @@ -833,22 +836,22 @@ Controller::simulation_methods(const Config &config, Method Controller::automatic_simulation_method( const Config &config, const Circuit &circ, const Noise::NoiseModel &noise_model) const { - // If circuit and noise model are Clifford run on Stabilizer simulator - if (validate_method(Method::stabilizer, config, circ, noise_model, false)) { - return Method::stabilizer; - } // For noisy simulations we enable the density matrix method if // shots > 2 ** num_qubits. This is based on a rough estimate that // a single shot of the density matrix simulator is approx 2 ** nq // times slower than a single shot of statevector due the increased // dimension - if (noise_model.has_quantum_errors() && circ.num_qubits < 64 && + if (noise_model.has_quantum_errors() && circ.num_qubits < 30 && circ.shots > (1ULL << circ.num_qubits) && validate_method(Method::density_matrix, config, circ, noise_model, false) && circ.can_sample) { return Method::density_matrix; } + // If circuit and noise model are Clifford run on Stabilizer simulator + if (validate_method(Method::stabilizer, config, circ, noise_model, false)) { + return Method::stabilizer; + } // If the special conditions for stabilizer or density matrix are // not satisfied we choose simulation method based on supported diff --git a/src/controllers/controller_execute.hpp b/src/controllers/controller_execute.hpp index f3128a7739..88d9c460f1 100644 --- a/src/controllers/controller_execute.hpp +++ b/src/controllers/controller_execute.hpp @@ -118,13 +118,13 @@ Result controller_execute(std::vector> &input_circs, param_circ->global_phase_for_params.resize(num_params); for (size_t j = 0; j < num_params; j++) param_circ->global_phase_for_params[j] = params.second[j]; - } else if (instr_pos >= num_instr) { + } else if ((uint_t)instr_pos >= num_instr) { throw std::invalid_argument( R"(Invalid parameterized qobj: instruction position out of range)"); } auto &op = param_circ->ops[instr_pos]; if (!op.has_bind_params) { - if (param_pos >= op.params.size()) { + if ((uint_t)param_pos >= op.params.size()) { throw std::invalid_argument( R"(Invalid parameterized qobj: instruction param position out of range)"); } @@ -160,7 +160,7 @@ Result controller_execute(std::vector> &input_circs, // negative position is for global phase circ->global_phase_angle = params.second[j]; } else { - if (instr_pos >= num_instr) { + if ((uint_t)instr_pos >= num_instr) { std::cout << "Invalid parameterization: instruction position " "out of range: " << instr_pos << std::endl; @@ -168,7 +168,7 @@ Result controller_execute(std::vector> &input_circs, R"(Invalid parameterization: instruction position out of range)"); } auto &op = param_circ->ops[instr_pos]; - if (param_pos >= op.params.size()) { + if ((uint_t)param_pos >= op.params.size()) { throw std::invalid_argument( R"(Invalid parameterization: instruction param position out of range)"); } @@ -215,7 +215,7 @@ Result controller_execute(std::vector> &input_circs, for (auto &circ : circs) { circ->seed = seed + seed_shift; circ->seed_for_params.resize(circ->num_bind_params); - for (int_t i = 0; i < circ->num_bind_params; i++) { + for (uint_t i = 0; i < circ->num_bind_params; i++) { circ->seed_for_params[i] = seed + seed_shift; seed_shift += 2113; } diff --git a/src/controllers/state_controller.hpp b/src/controllers/state_controller.hpp index 62d316b6e8..028806e822 100644 --- a/src/controllers/state_controller.hpp +++ b/src/controllers/state_controller.hpp @@ -630,7 +630,7 @@ void AerState::set_seed(int_t seed) { reg_t AerState::allocate_qubits(uint_t num_qubits) { assert_not_initialized(); reg_t ret; - for (auto i = 0; i < num_qubits; ++i) + for (uint_t i = 0; i < num_qubits; ++i) ret.push_back(num_of_qubits_++); return ret; }; @@ -816,7 +816,7 @@ reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t *data, reg_t ret; ret.reserve(num_of_qubits); - for (auto i = 0; i < num_of_qubits; ++i) + for (uint_t i = 0; i < num_of_qubits; ++i) ret.push_back(i); return ret; }; @@ -861,7 +861,7 @@ reg_t AerState::initialize_density_matrix(uint_t num_of_qubits, complex_t *data, reg_t ret; ret.reserve(num_of_qubits); - for (auto i = 0; i < num_of_qubits; ++i) + for (uint_t i = 0; i < num_of_qubits; ++i) ret.push_back(i); return ret; }; @@ -892,7 +892,7 @@ AER::Vector AerState::move_to_vector() { throw std::runtime_error("move_to_vector() supports only statevector or " "matrix_product_state or density_matrix methods"); } - for (auto i = 0; i < num_of_qubits_; ++i) + for (uint_t i = 0; i < num_of_qubits_; ++i) op.qubits.push_back(i); op.string_params.push_back("s"); op.save_type = Operations::DataSubType::single; @@ -907,7 +907,7 @@ AER::Vector AerState::move_to_vector() { .value()["s"] .value()); clear(); - return std::move(vec); + return vec; } else if (method_ == Method::density_matrix) { auto mat = std::move(static_cast, 1>>( @@ -917,7 +917,7 @@ AER::Vector AerState::move_to_vector() { auto vec = Vector::move_from_buffer( mat.GetColumns() * mat.GetRows(), mat.move_to_buffer()); clear(); - return std::move(vec); + return vec; } else { throw std::runtime_error("move_to_vector() supports only statevector or " "matrix_product_state or density_matrix methods"); @@ -941,7 +941,7 @@ matrix AerState::move_to_matrix() { throw std::runtime_error("move_to_matrix() supports only statevector or " "matrix_product_state or density_matrix methods"); } - for (auto i = 0; i < num_of_qubits_; ++i) + for (uint_t i = 0; i < num_of_qubits_; ++i) op.qubits.push_back(i); op.string_params.push_back("s"); op.save_type = Operations::DataSubType::single; @@ -966,7 +966,7 @@ matrix AerState::move_to_matrix() { .value())["s"] .value()); clear(); - return std::move(mat); + return mat; } else { throw std::runtime_error("move_to_matrix() supports only statevector or " "matrix_product_state or density_matrix methods"); diff --git a/src/framework/circuit.hpp b/src/framework/circuit.hpp index a21a7fbd8c..35e79e7b2b 100644 --- a/src/framework/circuit.hpp +++ b/src/framework/circuit.hpp @@ -135,20 +135,25 @@ class Circuit { void gate(const std::string &name, const reg_t &qubits, const std::vector ¶ms, const std::vector &string_params, - const int_t cond_regidx = -1, const std::string label = "") { + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr, + const std::string label = "") { ops.push_back(Operations::make_gate(name, qubits, params, string_params, - cond_regidx, label)); + cond_regidx, expr, label)); check_gate_params(ops.back()); } void diagonal(const reg_t &qubits, const cvector_t &vec, - const std::string &label) { - ops.push_back(Operations::make_diagonal(qubits, vec, label)); + const int_t cond_regidx = -1, const std::string label = "") { + ops.push_back(Operations::make_diagonal(qubits, vec, cond_regidx, label)); } void unitary(const reg_t &qubits, const cmatrix_t &mat, - const int_t cond_regidx = -1, const std::string label = "") { - ops.push_back(Operations::make_unitary(qubits, mat, cond_regidx, label)); + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr, + const std::string label = "") { + ops.push_back( + Operations::make_unitary(qubits, mat, cond_regidx, expr, label)); } void initialize(const reg_t &qubits, @@ -162,19 +167,23 @@ class Circuit { } void multiplexer(const reg_t &qubits, const std::vector &mats, - const int_t cond_regidx = -1, std::string label = "") { + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr, + std::string label = "") { ops.push_back( - Operations::make_multiplexer(qubits, mats, cond_regidx, label)); + Operations::make_multiplexer(qubits, mats, cond_regidx, expr, label)); } void kraus(const reg_t &qubits, const std::vector &mats, - const int_t cond_regidx = -1) { - ops.push_back(Operations::make_kraus(qubits, mats, cond_regidx)); + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr) { + ops.push_back(Operations::make_kraus(qubits, mats, cond_regidx, expr)); } void superop(const reg_t &qubits, const cmatrix_t &mat, - const int_t cond_regidx = -1) { - ops.push_back(Operations::make_superop(qubits, mat, cond_regidx)); + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr) { + ops.push_back(Operations::make_superop(qubits, mat, cond_regidx, expr)); } void save_state(const reg_t &qubits, const std::string &name, @@ -204,8 +213,10 @@ class Circuit { } void set_qerror_loc(const reg_t &qubits, const std::string &label, - const int_t conditional = -1) { - ops.push_back(Operations::make_qerror_loc(qubits, label, conditional)); + const int_t conditional = -1, + const std::shared_ptr expr = nullptr) { + ops.push_back( + Operations::make_qerror_loc(qubits, label, conditional, expr)); } template @@ -242,8 +253,9 @@ class Circuit { } void jump(const reg_t &qubits, const std::vector ¶ms, - const int_t cond_regidx = -1) { - ops.push_back(Operations::make_jump(qubits, params, cond_regidx)); + const int_t cond_regidx = -1, + const std::shared_ptr expr = nullptr) { + ops.push_back(Operations::make_jump(qubits, params, cond_regidx, expr)); } void mark(const reg_t &qubits, const std::vector ¶ms) { @@ -259,8 +271,8 @@ class Circuit { ops.push_back(Operations::make_measure(qubits, memory, registers)); } - void reset(const reg_t &qubits) { - ops.push_back(Operations::make_reset(qubits)); + void reset(const reg_t &qubits, const int_t cond_regidx = -1) { + ops.push_back(Operations::make_reset(qubits, cond_regidx)); } private: @@ -501,7 +513,7 @@ void Circuit::set_params(bool truncation) { } const auto &op = ops[pos]; - if (op.conditional) { + if (op.conditional || (op.type == OpType::jump && op.expr)) { can_sample = false; break; } diff --git a/src/framework/creg.hpp b/src/framework/creg.hpp index 1a0d012865..b9c93d3a06 100644 --- a/src/framework/creg.hpp +++ b/src/framework/creg.hpp @@ -136,6 +136,8 @@ bool ClassicalRegister::check_conditional(const Operations::Op &op) const { if (op.conditional) return (creg_register_[creg_register_.size() - op.conditional_reg - 1] == '1'); + if (op.expr) + return op.expr->eval_bool(creg_memory_); // Op is not conditional return true; @@ -186,23 +188,23 @@ void ClassicalRegister::apply_bfunc(const Operations::Op &op) { } // check value of compared integer for different comparison operations bool outcome; - switch (op.bfunc) { - case Operations::RegComparison::Equal: + switch (op.binary_op) { + case Operations::BinaryOp::Equal: outcome = (compared == 0); break; - case Operations::RegComparison::NotEqual: + case Operations::BinaryOp::NotEqual: outcome = (compared != 0); break; - case Operations::RegComparison::Less: + case Operations::BinaryOp::Less: outcome = (compared < 0); break; - case Operations::RegComparison::LessEqual: + case Operations::BinaryOp::LessEqual: outcome = (compared <= 0); break; - case Operations::RegComparison::Greater: + case Operations::BinaryOp::Greater: outcome = (compared > 0); break; - case Operations::RegComparison::GreaterEqual: + case Operations::BinaryOp::GreaterEqual: outcome = (compared >= 0); break; default: diff --git a/src/framework/json.hpp b/src/framework/json.hpp index 172f4eb1ee..f400641c50 100644 --- a/src/framework/json.hpp +++ b/src/framework/json.hpp @@ -263,7 +263,7 @@ void std::from_json(const json_t &js, template void std::to_json(json_t &js, const AER::Vector> &vec) { std::vector> out; - for (int64_t i = 0; i < vec.size(); ++i) { + for (size_t i = 0; i < vec.size(); ++i) { auto &z = vec[i]; out.push_back(std::vector{real(z), imag(z)}); } diff --git a/src/framework/linalg/vector.hpp b/src/framework/linalg/vector.hpp index 21cd0c9a7e..f8ee5bde84 100644 --- a/src/framework/linalg/vector.hpp +++ b/src/framework/linalg/vector.hpp @@ -35,7 +35,8 @@ T *malloc_data(size_t size) { // Data allocated here may need to be properly aligned to be compliant with // AVX2. void *data = nullptr; - posix_memalign(&data, 64, sizeof(T) * size); + if (posix_memalign(&data, 64, sizeof(T) * size) != 0) + throw std::runtime_error("Cannot allocate memory by posix_memalign"); return reinterpret_cast(data); #else return reinterpret_cast(malloc(sizeof(T) * size)); diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp old mode 100755 new mode 100644 index 335528de59..2f6a79adf6 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -28,12 +28,22 @@ #include "simulators/stabilizer/clifford.hpp" namespace AER { + +class ClassicalRegister; + namespace Operations { -// Comparisons enum class used for Boolean function operation. -// these are used to compare two hexadecimal strings and return a bool -// for now we only have one comparison Equal, but others will be added -enum class RegComparison { +// Operator enum class used for unary classical expression. +enum class UnaryOp { BitNot, LogicNot }; + +// Operator enum class used for binary classical expression or boolean +// function operation. +enum class BinaryOp { + BitAnd, + BitOr, + BitXor, + LogicAnd, + LogicOr, Equal, NotEqual, Less, @@ -42,6 +52,320 @@ enum class RegComparison { GreaterEqual }; +bool isBoolBinaryOp(const BinaryOp binary_op); +bool isBoolBinaryOp(const BinaryOp binary_op) { + return binary_op != BinaryOp::BitAnd && binary_op != BinaryOp::BitOr && + binary_op != BinaryOp::BitXor; +} + +uint_t truncate(const uint_t val, const size_t width); +uint_t truncate(const uint_t val, const size_t width) { + size_t shift = 64 - width; + return (val << shift) >> shift; +} + +enum class CExprType { Expr, Var, Value, Cast, Unary, Binary, Nop }; + +enum class ValueType { Bool, Uint }; + +class ScalarType { +public: + ScalarType(const ValueType _type, const size_t width_) + : type(_type), width(width_) {} + +public: + const ValueType type; + const size_t width; +}; + +template +inline std::shared_ptr get_wider_type(std::shared_ptr left, + std::shared_ptr right) { + if (left->width > right->width) + return left; + else + return right; +} + +class Uint : public ScalarType { +public: + Uint(const size_t size) : ScalarType(ValueType::Uint, size) {} +}; + +class Bool : public ScalarType { +public: + Bool() : ScalarType(ValueType::Bool, 1) {} +}; + +class CExpr { +public: + CExpr(const CExprType _expr_type, const std::shared_ptr _type) + : expr_type(_expr_type), type(_type) {} + virtual bool eval_bool(const std::string &memory) { return false; }; + virtual uint_t eval_uint(const std::string &memory) { return 0ul; }; + +public: + const CExprType expr_type; + const std::shared_ptr type; +}; + +class CastExpr : public CExpr { +public: + CastExpr(std::shared_ptr _type, + const std::shared_ptr operand_) + : CExpr(CExprType::Cast, _type), operand(operand_) {} + + virtual bool eval_bool(const std::string &memory) { + if (type->type != ValueType::Bool) + throw std::invalid_argument( + R"(eval_bool is called for non-bool expression.)"); + if (operand->type->type == ValueType::Bool) + return operand->eval_bool(memory); + else if (operand->type->type == ValueType::Uint) + return operand->eval_uint(memory) == 0ul; + else + throw std::invalid_argument(R"(invalid cast: from unknown type.)"); + } + + virtual uint_t eval_uint(const std::string &memory) { + if (type->type != ValueType::Uint) + throw std::invalid_argument( + R"(eval_uint is called for non-uint expression.)"); + if (operand->type->type == ValueType::Bool) + return operand->eval_bool(memory) ? 1ul : 0ul; + else if (operand->type->type == ValueType::Uint) + return truncate(operand->eval_uint(memory), type->width); + else + throw std::invalid_argument(R"(invalid cast: from unknown type.)"); + } + +public: + const std::shared_ptr operand; +}; + +class VarExpr : public CExpr { +public: + VarExpr(std::shared_ptr _type, + const std::vector &_cbit_idxs) + : CExpr(CExprType::Var, _type), cbit_idxs(_cbit_idxs) {} + + virtual bool eval_bool(const std::string &memory) { + if (type->type != ValueType::Bool) + throw std::invalid_argument( + R"(eval_bool is called for non-bool expression.)"); + return eval_uint_(memory) != 0ul; + } + + virtual uint_t eval_uint(const std::string &memory) { + if (type->type != ValueType::Uint) + throw std::invalid_argument( + R"(eval_uint is called for non-uint expression.)"); + return eval_uint_(memory); + } + +private: + uint_t eval_uint_(const std::string &memory) { + uint_t val = 0ul; + uint_t shift = 0; + for (const uint_t cbit_idx : cbit_idxs) { + if (memory.size() <= cbit_idx) + throw std::invalid_argument(R"(invalid cbit index.)"); + if (memory[memory.size() - cbit_idx - 1] == '1') + val |= (1 << shift); + ++shift; + } + return truncate(val, type->width); + } + +public: + const std::vector cbit_idxs; +}; + +class ValueExpr : public CExpr { +public: + ValueExpr(std::shared_ptr _type) + : CExpr(CExprType::Value, _type) {} +}; + +class UintValue : public ValueExpr { +public: + UintValue(size_t width, const uint_t value_) + : ValueExpr(std::make_shared(width)), value(value_) {} + + virtual bool eval_bool(const std::string &memory) { + throw std::invalid_argument( + R"(eval_bool is called for Uint value without cast.)"); + } + + virtual uint_t eval_uint(const std::string &memory) { return value; } + +public: + const uint_t value; +}; + +class BoolValue : public ValueExpr { +public: + BoolValue(const bool value_) + : ValueExpr(std::make_shared()), value(value_) {} + + virtual bool eval_bool(const std::string &memory) { return value != 0ul; } + + virtual uint_t eval_uint(const std::string &memory) { + throw std::invalid_argument( + R"(eval_uint is called for Bool value without cast.)"); + } + +public: + const bool value; +}; + +class UnaryExpr : public CExpr { +public: + UnaryExpr(const UnaryOp op_, const std::shared_ptr operand_) + : CExpr(CExprType::Unary, operand_->type), op(op_), operand(operand_) { + if (op == UnaryOp::LogicNot && operand_->type->type != ValueType::Bool) + throw std::invalid_argument( + R"(LogicNot unary expression must has Bool expression as its operand.)"); + + if (op == UnaryOp::BitNot && operand_->type->type != ValueType::Uint) + throw std::invalid_argument( + R"(BitNot unary expression must has Uint expression as its operand.)"); + } + + virtual bool eval_bool(const std::string &memory) { + if (op == UnaryOp::BitNot) + throw std::invalid_argument( + R"(eval_bool is called for BitNot unary expression.)"); + else // LogicNot + return !operand->eval_bool(memory); + } + + virtual uint_t eval_uint(const std::string &memory) { + if (op == UnaryOp::BitNot) + return truncate(~operand->eval_uint(memory), type->width); + else // LogicNot + throw std::invalid_argument( + R"(eval_uint is called for LogicNot unary expression.)"); + } + +public: + const UnaryOp op; + const std::shared_ptr operand; +}; + +class BinaryExpr : public CExpr { +public: + BinaryExpr(const BinaryOp op_, const std::shared_ptr left_, + const std::shared_ptr right_) + : CExpr(CExprType::Binary, + isBoolBinaryOp(op_) ? std::make_shared() + : get_wider_type(left_->type, right_->type)), + op(op_), left(left_), right(right_) { + + if (left->type->type != right->type->type) + throw std::invalid_argument( + R"(binary expression does not support different types in child expressions.)"); + + switch (op) { + case BinaryOp::BitAnd: + case BinaryOp::BitOr: + case BinaryOp::BitXor: + break; + case BinaryOp::LogicAnd: + case BinaryOp::LogicOr: + if (left->type->type != ValueType::Bool) + throw std::invalid_argument( + R"(logic operation allows only for bool expressions.)"); + break; + case BinaryOp::Equal: + case BinaryOp::NotEqual: + break; + case BinaryOp::Less: + case BinaryOp::LessEqual: + case BinaryOp::Greater: + case BinaryOp::GreaterEqual: + if (left->type->type != ValueType::Uint) + throw std::invalid_argument( + R"(comparison operation allows only for uint expressions.)"); + break; + default: + throw std::invalid_argument(R"(must not reach here.)"); + } + } + + virtual bool eval_bool(const std::string &memory) { + switch (op) { + case BinaryOp::BitAnd: + if (left->type->type == ValueType::Uint) + return eval_uint(memory) != 0; + else + return left->eval_bool(memory) && right->eval_bool(memory); + case BinaryOp::BitOr: + if (left->type->type == ValueType::Uint) + return eval_uint(memory) != 0; + else + return left->eval_bool(memory) || right->eval_bool(memory); + case BinaryOp::BitXor: + if (left->type->type == ValueType::Uint) + return eval_uint(memory) != 0; + else + return left->eval_bool(memory) ^ right->eval_bool(memory); + case BinaryOp::LogicAnd: + return left->eval_bool(memory) && right->eval_bool(memory); + case BinaryOp::LogicOr: + return left->eval_bool(memory) || right->eval_bool(memory); + case BinaryOp::Equal: + if (left->type->type == ValueType::Bool) + return left->eval_bool(memory) == right->eval_bool(memory); + else + return left->eval_uint(memory) == right->eval_uint(memory); + case BinaryOp::NotEqual: + if (left->type->type == ValueType::Bool) + return left->eval_bool(memory) != right->eval_bool(memory); + else + return left->eval_uint(memory) != right->eval_uint(memory); + case BinaryOp::Less: + return left->eval_uint(memory) < right->eval_uint(memory); + case BinaryOp::LessEqual: + return left->eval_uint(memory) <= right->eval_uint(memory); + case BinaryOp::Greater: + return left->eval_uint(memory) > right->eval_uint(memory); + case BinaryOp::GreaterEqual: + return left->eval_uint(memory) >= right->eval_uint(memory); + default: + throw std::invalid_argument(R"(must not reach here.)"); + } + } + + virtual uint_t eval_uint(const std::string &memory) { + switch (op) { + case BinaryOp::BitAnd: + return left->eval_uint(memory) & right->eval_uint(memory); + case BinaryOp::BitOr: + return left->eval_uint(memory) | right->eval_uint(memory); + case BinaryOp::BitXor: + return left->eval_uint(memory) ^ right->eval_uint(memory); + case BinaryOp::LogicAnd: + case BinaryOp::LogicOr: + case BinaryOp::Equal: + case BinaryOp::NotEqual: + case BinaryOp::Less: + case BinaryOp::LessEqual: + case BinaryOp::Greater: + case BinaryOp::GreaterEqual: + throw std::invalid_argument( + R"(eval_uint is called for binary expression that returns bool.)"); + default: + throw std::invalid_argument(R"(must not reach here.)"); + } + } + +public: + const BinaryOp op; + const std::shared_ptr left; + const std::shared_ptr right; +}; + // Enum class for operation types enum class OpType { gate, @@ -87,7 +411,9 @@ enum class OpType { set_mps, // Control Flow jump, - mark + mark, + unary_expr, + binary_expr }; enum class DataSubType { @@ -229,6 +555,12 @@ inline std::ostream &operator<<(std::ostream &stream, const OpType &type) { case OpType::jump: stream << "jump"; break; + case OpType::unary_expr: + stream << "unary_expr"; + break; + case OpType::binary_expr: + stream << "binary_expr"; + break; default: stream << "unknown"; } @@ -287,7 +619,8 @@ struct Op { bool conditional = false; // is gate conditional gate uint_t conditional_reg; // (opt) the (single) register location to look up for // conditional - RegComparison bfunc; // (opt) boolean function relation + BinaryOp binary_op; // (opt) boolean function relation + std::shared_ptr expr; // (opt) classical expression // Measurement reg_t memory; // (opt) register operation it acts on (measure) @@ -439,7 +772,9 @@ inline Op make_initialize(const reg_t &qubits, } inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, - const int_t conditional = -1, std::string label = "") { + const int_t conditional = -1, + const std::shared_ptr expr = nullptr, + std::string label = "") { Op op; op.type = OpType::matrix; op.name = "unitary"; @@ -449,6 +784,7 @@ inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; if (label != "") op.string_params = {label}; return op; @@ -468,6 +804,7 @@ inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat, } inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, + const int_t conditional = -1, const std::string label = "") { Op op; op.type = OpType::diagonal_matrix; @@ -475,6 +812,11 @@ inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, op.qubits = qubits; op.params = vec; + if (conditional >= 0) { + op.conditional = true; + op.conditional_reg = conditional; + } + if (label != "") op.string_params = {label}; @@ -482,6 +824,7 @@ inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, } inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, + const int_t conditional = -1, const std::string label = "") { Op op; op.type = OpType::diagonal_matrix; @@ -489,6 +832,11 @@ inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, op.qubits = qubits; op.params = std::move(vec); + if (conditional >= 0) { + op.conditional = true; + op.conditional_reg = conditional; + } + if (label != "") op.string_params = {label}; @@ -496,7 +844,8 @@ inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, } inline Op make_superop(const reg_t &qubits, const cmatrix_t &mat, - const int_t conditional = -1) { + const int_t conditional = -1, + const std::shared_ptr expr = nullptr) { Op op; op.type = OpType::superop; op.name = "superop"; @@ -506,6 +855,7 @@ inline Op make_superop(const reg_t &qubits, const cmatrix_t &mat, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; return op; } @@ -520,7 +870,8 @@ inline Op make_superop(const reg_t &qubits, cmatrix_t &&mat) { } inline Op make_kraus(const reg_t &qubits, const std::vector &mats, - const int_t conditional = -1) { + const int_t conditional = -1, + const std::shared_ptr expr = nullptr) { Op op; op.type = OpType::kraus; op.name = "kraus"; @@ -530,6 +881,7 @@ inline Op make_kraus(const reg_t &qubits, const std::vector &mats, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; return op; } @@ -578,13 +930,13 @@ inline Op make_bfunc(const std::string &mask, const std::string &val, Utils::format_hex_inplace(op.string_params[0]); Utils::format_hex_inplace(op.string_params[1]); - const stringmap_t comp_table({ - {"==", RegComparison::Equal}, - {"!=", RegComparison::NotEqual}, - {"<", RegComparison::Less}, - {"<=", RegComparison::LessEqual}, - {">", RegComparison::Greater}, - {">=", RegComparison::GreaterEqual}, + const stringmap_t comp_table({ + {"==", BinaryOp::Equal}, + {"!=", BinaryOp::NotEqual}, + {"<", BinaryOp::Less}, + {"<=", BinaryOp::LessEqual}, + {">", BinaryOp::Greater}, + {">=", BinaryOp::GreaterEqual}, }); auto it = comp_table.find(relation); @@ -594,7 +946,7 @@ inline Op make_bfunc(const std::string &mask, const std::string &val, << std::endl; throw std::invalid_argument(msg.str()); } else { - op.bfunc = it->second; + op.binary_op = it->second; } return op; @@ -603,7 +955,13 @@ inline Op make_bfunc(const std::string &mask, const std::string &val, Op make_gate(const std::string &name, const reg_t &qubits, const std::vector ¶ms, const std::vector &string_params, - const int_t conditional, const std::string &label) { + const int_t conditional, const std::shared_ptr expr, + const std::string &label); +Op make_gate(const std::string &name, const reg_t &qubits, + const std::vector ¶ms, + const std::vector &string_params, + const int_t conditional, const std::shared_ptr expr, + const std::string &label) { Op op; op.type = OpType::gate; op.name = name; @@ -616,6 +974,7 @@ Op make_gate(const std::string &name, const reg_t &qubits, op.string_params = {label}; else op.string_params = {op.name}; + op.expr = expr; if (conditional >= 0) { op.conditional = true; @@ -658,17 +1017,24 @@ inline Op make_u3(uint_t qubit, T theta, T phi, T lam) { return op; } -inline Op make_reset(const reg_t &qubits, uint_t state = 0) { +inline Op make_reset(const reg_t &qubits, const int_t conditional) { Op op; op.type = OpType::reset; op.name = "reset"; op.qubits = qubits; + + if (conditional >= 0) { + op.conditional = true; + op.conditional_reg = conditional; + } + return op; } inline Op make_multiplexer(const reg_t &qubits, const std::vector &mats, const int_t conditional = -1, + const std::shared_ptr expr = nullptr, std::string label = "") { // Check matrices are N-qubit @@ -717,6 +1083,7 @@ inline Op make_multiplexer(const reg_t &qubits, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; // Validate qubits are unique. check_empty_qubits(op); @@ -879,7 +1246,8 @@ inline Op make_set_clifford(const reg_t &qubits, const std::string &name, } inline Op make_jump(const reg_t &qubits, const std::vector ¶ms, - const int_t conditional) { + const int_t conditional, + const std::shared_ptr expr = nullptr) { Op op; op.type = OpType::jump; op.name = "jump"; @@ -893,6 +1261,7 @@ inline Op make_jump(const reg_t &qubits, const std::vector ¶ms, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; return op; } @@ -931,7 +1300,8 @@ inline Op make_measure(const reg_t &qubits, const reg_t &memory, } inline Op make_qerror_loc(const reg_t &qubits, const std::string &label, - const int_t conditional = -1) { + const int_t conditional = -1, + const std::shared_ptr expr = nullptr) { Op op; op.type = OpType::qerror_loc; op.name = label; @@ -940,6 +1310,7 @@ inline Op make_qerror_loc(const reg_t &qubits, const std::string &label, op.conditional = true; op.conditional_reg = conditional; } + op.expr = expr; return op; } @@ -956,12 +1327,12 @@ inline Op bind_parameter(const Op &src, const uint_t iparam, if (src.params.size() > 0) { uint_t stride = src.params.size() / num_params; op.params.resize(stride); - for (int_t i = 0; i < stride; i++) + for (uint_t i = 0; i < stride; i++) op.params[i] = src.params[iparam * stride + i]; } else if (src.mats.size() > 0) { uint_t stride = src.mats.size() / num_params; op.mats.resize(stride); - for (int_t i = 0; i < stride; i++) + for (uint_t i = 0; i < stride; i++) op.mats[i] = src.mats[iparam * stride + i]; } return op; @@ -1171,6 +1542,7 @@ json_t op_to_json(const Op &op) { return ret; } +void to_json(json_t &js, const OpType &type); void to_json(json_t &js, const OpType &type) { std::stringstream ss; ss << type; @@ -1368,13 +1740,13 @@ Op input_to_op_bfunc(const inputdata_t &input) { Utils::format_hex_inplace(op.string_params[0]); Utils::format_hex_inplace(op.string_params[1]); - const stringmap_t comp_table({ - {"==", RegComparison::Equal}, - {"!=", RegComparison::NotEqual}, - {"<", RegComparison::Less}, - {"<=", RegComparison::LessEqual}, - {">", RegComparison::Greater}, - {">=", RegComparison::GreaterEqual}, + const stringmap_t comp_table({ + {"==", BinaryOp::Equal}, + {"!=", BinaryOp::NotEqual}, + {"<", BinaryOp::Less}, + {"<=", BinaryOp::LessEqual}, + {">", BinaryOp::Greater}, + {">=", BinaryOp::GreaterEqual}, }); auto it = comp_table.find(relation); @@ -1384,7 +1756,7 @@ Op input_to_op_bfunc(const inputdata_t &input) { << std::endl; throw std::invalid_argument(msg.str()); } else { - op.bfunc = it->second; + op.binary_op = it->second; } // Conditional @@ -1498,7 +1870,7 @@ Op input_to_op_multiplexer(const inputdata_t &input) { Parser::get_value(mats, "params", input); Parser::get_value(label, "label", input); // Construct op - auto op = make_multiplexer(qubits, mats, -1, label); + auto op = make_multiplexer(qubits, mats, -1, nullptr, label); // Conditional add_conditional(Allowed::Yes, op, input); return op; diff --git a/src/framework/pybind_json.hpp b/src/framework/pybind_json.hpp index 7ac889c3c2..108e1b34ec 100644 --- a/src/framework/pybind_json.hpp +++ b/src/framework/pybind_json.hpp @@ -32,6 +32,8 @@ #include "misc/warnings.hpp" DISABLE_WARNING_PUSH +#pragma GCC diagnostic ignored "-Wfloat-equal" + #include #include #include @@ -40,6 +42,7 @@ DISABLE_WARNING_PUSH #include DISABLE_WARNING_POP +#pragma GCC diagnostic warning "-Wfloat-equal" #include "framework/json.hpp" @@ -293,7 +296,7 @@ void std::from_json(const json_t &js, py::object &o) { o = py::str(js.get()); } else if (js.is_array()) { std::vector obj(js.size()); - for (auto i = 0; i < js.size(); i++) { + for (size_t i = 0; i < js.size(); i++) { py::object tmp; from_json(js[i], tmp); obj[i] = tmp; diff --git a/src/framework/qobj.hpp b/src/framework/qobj.hpp index 01084fd20e..2a25f8cfe2 100644 --- a/src/framework/qobj.hpp +++ b/src/framework/qobj.hpp @@ -155,12 +155,12 @@ Qobj::Qobj(const inputdata_t &input) { // negative position is for global phase param_circuit->global_phase_angle = params.second[j]; } else { - if (instr_pos >= num_instr) { + if ((uint_t)instr_pos >= num_instr) { throw std::invalid_argument( R"(Invalid parameterized qobj: instruction position out of range)"); } auto &op = param_circuit->ops[instr_pos]; - if (param_pos >= op.params.size()) { + if ((uint_t)param_pos >= op.params.size()) { throw std::invalid_argument( R"(Invalid parameterized qobj: instruction param position out of range)"); } diff --git a/src/framework/utils.hpp b/src/framework/utils.hpp old mode 100755 new mode 100644 index 6c3cc52d77..8e750e336d --- a/src/framework/utils.hpp +++ b/src/framework/utils.hpp @@ -28,8 +28,11 @@ #include #endif -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) #include +#elif defined(__APPLE__) +#include +#include #elif defined(_WIN64) || defined(_WIN32) // This is needed because windows.h redefine min()/max() so interferes with // std::min/max @@ -1267,13 +1270,16 @@ uint_t (*popcount)(uint_t) = is_avx2_supported() ? &_instrinsic_weight bool (*hamming_parity)(uint_t) = &_naive_parity; uint_t (*popcount)(uint_t) = &_naive_weight; #endif - +size_t get_system_memory_mb(); size_t get_system_memory_mb() { size_t total_physical_memory = 0; -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) size_t pages = (size_t)sysconf(_SC_PHYS_PAGES); size_t page_size = (size_t)sysconf(_SC_PAGE_SIZE); total_physical_memory = pages * page_size; +#elif defined(__APPLE__) + size_t len = sizeof(total_physical_memory); + sysctlbyname("hw.memsize", &total_physical_memory, &len, NULL, 0); #elif defined(_WIN64) || defined(_WIN32) MEMORYSTATUSEX status; status.dwLength = sizeof(status); diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index ef3df0a4ce..23dbccc9bd 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -292,7 +292,7 @@ NoiseModel::NoiseOps NoiseModel::sample_noise_loc(const Operations::Op &op, for (auto &noise_op : noise_ops) { noise_op.conditional = op.conditional; noise_op.conditional_reg = op.conditional_reg; - noise_op.bfunc = op.bfunc; + noise_op.binary_op = op.binary_op; } } return noise_ops; @@ -374,7 +374,7 @@ NoiseModel::NoiseOps NoiseModel::sample_noise_op(const Operations::Op &op, for (auto &noise_op : noise_ops) { noise_op.conditional = op.conditional; noise_op.conditional_reg = op.conditional_reg; - noise_op.bfunc = op.bfunc; + noise_op.binary_op = op.binary_op; } } return noise_ops; @@ -386,7 +386,7 @@ void NoiseModel::enable_superop_method(int num_threads) { exs.resize(std::max(num_threads, 1)); #pragma omp parallel for if (num_threads > 1 && quantum_errors_.size() > 10) \ num_threads(num_threads) - for (int i = 0; i < quantum_errors_.size(); i++) { + for (int i = 0; i < (int_t)quantum_errors_.size(); i++) { try { quantum_errors_[i].compute_superoperator(); } catch (...) { @@ -406,7 +406,7 @@ void NoiseModel::enable_kraus_method(int num_threads) { exs.resize(std::max(num_threads, 1)); #pragma omp parallel for if (num_threads > 1 && quantum_errors_.size() > 10) \ num_threads(num_threads) - for (int i = 0; i < quantum_errors_.size(); i++) { + for (int i = 0; i < (int_t)quantum_errors_.size(); i++) { try { quantum_errors_[i].compute_kraus(); } catch (...) { @@ -851,6 +851,8 @@ cmatrix_t NoiseModel::op2superop(const Operations::Op &op) const { case ParamGate::cu: return Linalg::SMatrix::cu(op.params[0], op.params[1], op.params[2], op.params[3]); + default: + break; } } else { // Check if we can convert this gate to a standard superoperator matrix @@ -897,6 +899,8 @@ cmatrix_t NoiseModel::op2unitary(const Operations::Op &op) const { return Linalg::Matrix::rzx(op.params[0]); case ParamGate::cp: return Linalg::Matrix::cphase(op.params[0]); + default: + break; } } else { // Check if we can convert this gate to a standard superoperator matrix diff --git a/src/simulators/batch_shots_executor.hpp b/src/simulators/batch_shots_executor.hpp index 0c4a67cb56..612e5ed289 100644 --- a/src/simulators/batch_shots_executor.hpp +++ b/src/simulators/batch_shots_executor.hpp @@ -133,7 +133,7 @@ void BatchShotsExecutor::set_parallelization( enable_batch_multi_shots_ = false; if (batched_shots_gpu_ && Base::sim_device_ != Device::CPU) { enable_batch_multi_shots_ = true; - if (circ.num_qubits > batched_shots_gpu_max_qubits_) + if (circ.num_qubits > (uint_t)batched_shots_gpu_max_qubits_) enable_batch_multi_shots_ = false; else if (circ.shots == 1 && circ.num_bind_params == 1) enable_batch_multi_shots_ = false; @@ -150,15 +150,13 @@ template void BatchShotsExecutor::run_circuit_with_sampling( Circuit &circ, const Config &config, RngEngine &init_rng, ResultItr result_it) { - if (circ.num_bind_params == 1 || !enable_batch_multi_shots_) { + if (!enable_batch_multi_shots_) { return Executor::run_circuit_with_sampling(circ, config, init_rng, result_it); } - Noise::NoiseModel dummy_noise; state_t dummy_state; - int_t i; - int_t i_begin, n_shots; + uint_t i_begin, n_shots; Base::num_qubits_ = circ.num_qubits; Base::num_creg_memory_ = circ.num_memory; @@ -196,7 +194,7 @@ void BatchShotsExecutor::run_circuit_with_sampling( fusion_result); auto time_taken = std::chrono::duration(myclock_t::now() - timer_start).count(); - for (i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.copy(fusion_result.metadata); // Add batched multi-shots optimizaiton metadata @@ -223,13 +221,13 @@ void BatchShotsExecutor::run_circuit_with_sampling( while (i_begin < Base::num_local_states_) { // loop for states can be stored in available memory n_shots = Base::num_local_states_ - i_begin; - n_shots = std::min(n_shots, (int_t)Base::num_max_shots_); + n_shots = std::min(n_shots, Base::num_max_shots_); // allocate shots this->allocate_states(n_shots, config); // Set state config - for (i = 0; i < n_shots; i++) { + for (uint_t i = 0; i < n_shots; i++) { Base::states_[i].set_parallelization(Base::parallel_state_update_); } @@ -257,7 +255,7 @@ void BatchShotsExecutor::run_circuit_with_sampling( auto apply_ops_lambda = [this, circ, init_rng, first_meas, final_ops, dummy_noise, &result_it](int_t i) { std::vector rng(Base::num_states_in_group_[i]); - for (int_t j = 0; j < Base::num_states_in_group_[i]; j++) { + for (uint_t j = 0; j < Base::num_states_in_group_[i]; j++) { uint_t iparam = Base::global_state_index_ + Base::top_state_of_group_[i] + j; if (iparam == 0) @@ -285,8 +283,8 @@ void BatchShotsExecutor::run_circuit_with_sampling( if (Base::num_process_per_experiment_ > 1) { Base::gather_creg_memory(Base::cregs_, Base::state_index_begin_); - for (i = 0; i < circ.num_bind_params; i++) { - for (int_t j = 0; j < circ.shots; j++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t j = 0; j < circ.shots; j++) { (result_it + i) ->save_count_data(Base::cregs_[i * circ.shots + j], Base::save_creg_memory_); @@ -305,7 +303,7 @@ void BatchShotsExecutor::run_circuit_with_sampling( } if (nDev > Base::num_groups_) nDev = Base::num_groups_; - for (i = 0; i < circ.num_bind_params; i++) + for (uint_t i = 0; i < circ.num_bind_params; i++) (result_it + i) ->metadata.add(nDev, "batched_shots_optimization_parallel_gpus"); } @@ -363,10 +361,9 @@ void BatchShotsExecutor::run_circuit_shots( Base::max_matrix_qubits_ = Base::get_max_matrix_qubits(circ_opt); - int_t i; - int_t i_begin, n_shots; + uint_t i_begin, n_shots; - for (i = 0; i < Base::num_bind_params_; i++) { + for (uint_t i = 0; i < Base::num_bind_params_; i++) { ExperimentResult &result = *(result_it + i); result.metadata.copy(fusion_result.metadata); // Add batched multi-shots optimizaiton metadata @@ -383,13 +380,13 @@ void BatchShotsExecutor::run_circuit_shots( while (i_begin < Base::num_local_states_) { // loop for states can be stored in available memory n_shots = Base::num_local_states_ - i_begin; - n_shots = std::min(n_shots, (int_t)Base::num_max_shots_); + n_shots = std::min(n_shots, Base::num_max_shots_); // allocate shots this->allocate_states(n_shots, config); // Set state config - for (i = 0; i < n_shots; i++) { + for (uint_t i = 0; i < n_shots; i++) { Base::states_[i].set_parallelization(Base::parallel_state_update_); } @@ -419,7 +416,7 @@ void BatchShotsExecutor::run_circuit_shots( noise](int_t i) { par_results[i].resize(circ.num_bind_params); std::vector rng(Base::num_states_in_group_[i]); - for (int_t j = 0; j < Base::num_states_in_group_[i]; j++) { + for (uint_t j = 0; j < Base::num_states_in_group_[i]; j++) { uint_t ishot = Base::global_state_index_ + Base::top_state_of_group_[i] + j; uint_t iparam = ishot / Base::num_shots_per_bind_param_; @@ -442,13 +439,13 @@ void BatchShotsExecutor::run_circuit_shots( Base::num_groups_, apply_ops_lambda, Base::num_groups_); for (auto &res : par_results) { - for (i = 0; i < Base::num_bind_params_; i++) { + for (uint_t i = 0; i < Base::num_bind_params_; i++) { (result_it + i)->combine(std::move(res[i])); } } // collect measured bits and copy memory - for (i = 0; i < n_shots; i++) { + for (uint_t i = 0; i < n_shots; i++) { if (Base::num_process_per_experiment_ > 1) { Base::states_[i].qreg().read_measured_data( Base::cregs_[Base::global_state_index_ + i_begin + i]); @@ -470,7 +467,7 @@ void BatchShotsExecutor::run_circuit_shots( if (Base::num_process_per_experiment_ > 1) { Base::gather_creg_memory(Base::cregs_, Base::state_index_begin_); - for (i = 0; i < circ_opt.shots; i++) { + for (uint_t i = 0; i < circ_opt.shots; i++) { uint_t iparam = i / Base::num_shots_per_bind_param_; (result_it + iparam) ->save_count_data(Base::cregs_[i], Base::save_creg_memory_); @@ -488,7 +485,7 @@ void BatchShotsExecutor::run_circuit_shots( } if (nDev > Base::num_groups_) nDev = Base::num_groups_; - for (i = 0; i < Base::num_bind_params_; i++) + for (uint_t i = 0; i < Base::num_bind_params_; i++) (result_it + i) ->metadata.add(nDev, "batched_shots_optimization_parallel_gpus"); } @@ -510,6 +507,23 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( for (auto op = first; op != last; ++op) { if (op->type == Operations::OpType::sample_noise) { + if (op->expr) { + for (uint_t j = Base::top_state_of_group_[i_group]; + j < Base::top_state_of_group_[i_group + 1]; j++) { + Base::states_[j].qreg().enable_batch(false); + Base::states_[j].qreg().read_measured_data(Base::states_[j].creg()); + std::vector nops = noise.sample_noise_loc( + *op, rng[j - Base::top_state_of_group_[i_group]]); + for (uint_t k = 0; k < nops.size(); k++) { + Base::states_[j].apply_op( + nops[k], *result_it, + rng[j - Base::top_state_of_group_[i_group]], false); + } + Base::states_[j].qreg().enable_batch(true); + } + continue; + } + // sample error here uint_t count = Base::num_states_in_group_[i_group]; std::vector> noise_ops(count); @@ -518,13 +532,13 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( uint_t non_pauli_gate_count = 0; if (num_inner_threads > 1) { #pragma omp parallel for reduction(+: count_ops,non_pauli_gate_count) num_threads(num_inner_threads) - for (int_t j = 0; j < count; j++) { + for (int_t j = 0; j < (int_t)count; j++) { noise_ops[j] = noise.sample_noise_loc(*op, rng[j]); if (!(noise_ops[j].size() == 0 || (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { count_ops++; - for (int_t k = 0; k < noise_ops[j].size(); k++) { + for (uint_t k = 0; k < noise_ops[j].size(); k++) { if (noise_ops[j][k].name != "id" && noise_ops[j][k].name != "x" && noise_ops[j][k].name != "y" && noise_ops[j][k].name != "z" && noise_ops[j][k].name != "pauli") { @@ -535,13 +549,13 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( } } } else { - for (int_t j = 0; j < count; j++) { + for (uint_t j = 0; j < count; j++) { noise_ops[j] = noise.sample_noise_loc(*op, rng[j]); if (!(noise_ops[j].size() == 0 || (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { count_ops++; - for (int_t k = 0; k < noise_ops[j].size(); k++) { + for (uint_t k = 0; k < noise_ops[j].size(); k++) { if (noise_ops[j][k].name != "id" && noise_ops[j][k].name != "x" && noise_ops[j][k].name != "y" && noise_ops[j][k].name != "z" && noise_ops[j][k].name != "pauli") { @@ -563,19 +577,20 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( apply_batched_noise_ops(i_group, noise_ops, result_it, rng); } } else { - if (!apply_batched_op(istate, *op, result_it, rng, - final_ops && (op + 1 == last))) { - // call apply_op for each state - for (int_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { - uint_t is = Base::top_state_of_group_[i_group] + j; - uint_t ip = (Base::global_state_index_ + is) / - Base::num_shots_per_bind_param_; - Base::states_[is].qreg().enable_batch(false); - Base::states_[is].qreg().read_measured_data(Base::states_[is].creg()); - Base::states_[is].apply_op(*op, *(result_it + ip), rng[j], - final_ops && (op + 1 == last)); - Base::states_[is].qreg().enable_batch(true); - } + if (!op->expr && apply_batched_op(istate, *op, result_it, rng, + final_ops && (op + 1 == last))) { + continue; + } + // call apply_op for each state + for (uint_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { + uint_t is = Base::top_state_of_group_[i_group] + j; + uint_t ip = + (Base::global_state_index_ + is) / Base::num_shots_per_bind_param_; + Base::states_[is].qreg().enable_batch(false); + Base::states_[is].qreg().read_measured_data(Base::states_[is].creg()); + Base::states_[is].apply_op(*op, *(result_it + ip), rng[j], + final_ops && (op + 1 == last)); + Base::states_[is].qreg().enable_batch(true); } } } @@ -585,13 +600,13 @@ template void BatchShotsExecutor::apply_batched_noise_ops( const int_t i_group, const std::vector> &ops, ResultItr result_it, std::vector &rng) { - int_t i, j, k, count, nop, pos = 0; + uint_t count; uint_t istate = Base::top_state_of_group_[i_group]; count = ops.size(); reg_t mask(count); std::vector finished(count, false); - for (i = 0; i < count; i++) { + for (uint_t i = 0; i < count; i++) { int_t cond_reg = -1; if (finished[i]) @@ -603,7 +618,7 @@ void BatchShotsExecutor::apply_batched_noise_ops( mask[i] = 1; // find same ops to be exectuted in a batch - for (j = i + 1; j < count; j++) { + for (uint_t j = i + 1; j < count; j++) { if (finished[j]) { mask[j] = 0; continue; @@ -621,7 +636,7 @@ void BatchShotsExecutor::apply_batched_noise_ops( } mask[j] = true; - for (k = 0; k < ops[i].size(); k++) { + for (uint_t k = 0; k < ops[i].size(); k++) { if (ops[i][k].conditional) { cond_reg = ops[i][k].conditional_reg; } @@ -640,7 +655,7 @@ void BatchShotsExecutor::apply_batched_noise_ops( cond_reg, mask); // batched execution on same ops - for (k = 0; k < ops[i].size(); k++) { + for (uint_t k = 0; k < ops[i].size(); k++) { Operations::Op cop = ops[i][k]; // mark op conditional to mask shots @@ -649,7 +664,7 @@ void BatchShotsExecutor::apply_batched_noise_ops( if (!apply_batched_op(istate, cop, result_it, rng, false)) { // call apply_op for each state - for (int_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { + for (uint_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { uint_t is = Base::top_state_of_group_[i_group] + j; uint_t ip = (Base::global_state_index_ + is) / Base::num_shots_per_bind_param_; @@ -671,7 +686,7 @@ void BatchShotsExecutor::apply_batched_expval(const int_t istate, ResultItr result) { std::vector val; bool variance = (op.type == Operations::OpType::save_expval_var); - for (int_t i = 0; i < op.expval_params.size(); i++) { + for (uint_t i = 0; i < op.expval_params.size(); i++) { std::complex cprm; if (variance) @@ -689,7 +704,7 @@ void BatchShotsExecutor::apply_batched_expval(const int_t istate, return; if (variance) { - for (int_t i = 0; i < val.size() / 2; i++) { + for (uint_t i = 0; i < val.size() / 2; i++) { uint_t ip = (Base::global_state_index_ + istate + i) / Base::num_shots_per_bind_param_; @@ -702,7 +717,7 @@ void BatchShotsExecutor::apply_batched_expval(const int_t istate, op.save_type); } } else { - for (int_t i = 0; i < val.size(); i++) { + for (uint_t i = 0; i < val.size(); i++) { uint_t ip = (Base::global_state_index_ + istate + i) / Base::num_shots_per_bind_param_; @@ -720,7 +735,7 @@ void BatchShotsExecutor::batched_measure_sampler( InputIterator first_meas, InputIterator last_meas, uint_t shots, uint_t i_group, ResultItr result, std::vector &rng) { uint_t par_states = 1; - if (Base::max_parallel_threads_ >= Base::num_groups_ * 2) { + if ((uint_t)Base::max_parallel_threads_ >= Base::num_groups_ * 2) { par_states = std::min((uint_t)(Base::max_parallel_threads_ / Base::num_groups_), Base::num_states_in_group_[i_group]); @@ -781,7 +796,7 @@ void BatchShotsExecutor::batched_measure_sampler( state_end = Base::num_states_in_group_[i_group] * (i + 1) / par_states; for (; i_state < state_end; i_state++) { - for (int_t j = 0; j < shots; j++) + for (uint_t j = 0; j < shots; j++) rnd_shots[i_state * shots + j] = rng[i_state].rand(0, 1) + (double)i_state; } @@ -813,14 +828,14 @@ void BatchShotsExecutor::batched_measure_sampler( uint_t is = Base::top_state_of_group_[i_group] + i_state; uint_t ip = (Base::global_state_index_ + is); - for (int_t i = 0; i < shots; i++) { + for (uint_t i = 0; i < shots; i++) { ClassicalRegister creg; creg.initialize(num_memory, num_registers); reg_t all_samples(meas_qubits.size()); uint_t val = allbit_samples[i_state * shots + i] & mask; reg_t allbit_sample = Utils::int2reg(val, 2, Base::num_qubits_); - for (int_t mq = 0; mq < meas_qubits.size(); mq++) { + for (uint_t mq = 0; mq < meas_qubits.size(); mq++) { all_samples[mq] = allbit_sample[meas_qubits[mq]]; } @@ -853,7 +868,7 @@ void BatchShotsExecutor::batched_measure_sampler( auto time_taken = std::chrono::duration(myclock_t::now() - timer_start).count(); - for (int_t i_state = 0; i_state < Base::num_states_in_group_[i_group]; + for (uint_t i_state = 0; i_state < Base::num_states_in_group_[i_group]; i_state++) { uint_t ip = Base::global_state_index_ + Base::top_state_of_group_[i_group] + i_state; diff --git a/src/simulators/chunk_utils.hpp b/src/simulators/chunk_utils.hpp index 3277e2c0fd..fa52c6282f 100644 --- a/src/simulators/chunk_utils.hpp +++ b/src/simulators/chunk_utils.hpp @@ -22,13 +22,22 @@ namespace AER { namespace Chunk { +void get_qubits_inout(const int chunk_qubits, const reg_t &qubits, + reg_t &qubits_in, reg_t &qubits_out); +void get_inout_ctrl_qubits(const Operations::Op &op, const uint_t num_qubits, + reg_t &qubits_in, reg_t &qubits_out); +Operations::Op correct_gate_op_in_chunk(const Operations::Op &op, + reg_t &qubits_in); +void block_diagonal_matrix(const uint_t gid, const uint_t chunk_bits, + reg_t &qubits, cvector_t &diag); + void get_qubits_inout(const int chunk_qubits, const reg_t &qubits, reg_t &qubits_in, reg_t &qubits_out) { - int_t i; + uint_t i; qubits_in.clear(); qubits_out.clear(); for (i = 0; i < qubits.size(); i++) { - if (qubits[i] < chunk_qubits) { // in chunk + if (qubits[i] < (uint_t)chunk_qubits) { // in chunk qubits_in.push_back(qubits[i]); } else { qubits_out.push_back(qubits[i]); @@ -40,7 +49,7 @@ void get_inout_ctrl_qubits(const Operations::Op &op, const uint_t num_qubits, reg_t &qubits_in, reg_t &qubits_out) { if (op.type == Operations::OpType::gate && (op.name[0] == 'c' || op.name.find("mc") == 0)) { - for (int i = 0; i < op.qubits.size(); i++) { + for (uint_t i = 0; i < op.qubits.size(); i++) { if (op.qubits[i] < num_qubits) qubits_in.push_back(op.qubits[i]); else diff --git a/src/simulators/circuit_executor.hpp b/src/simulators/circuit_executor.hpp index b5ea6193a0..e49eef13f2 100644 --- a/src/simulators/circuit_executor.hpp +++ b/src/simulators/circuit_executor.hpp @@ -101,6 +101,9 @@ class Executor : public Base { int parallel_shots_; int parallel_state_update_; + // OpenMP qubit threshold + int omp_qubit_threshold_ = 14; + // results are stored independently in each process if true bool accept_distributed_results_ = true; @@ -111,7 +114,7 @@ class Executor : public Base { uint_t distributed_group_; // group id of distribution int_t distributed_proc_bits_; // distributed_procs_=2^distributed_proc_bits_ // (if nprocs != power of 2, set -1) - int num_process_per_experiment_ = 1; + uint_t num_process_per_experiment_ = 1; #ifdef AER_MPI // communicator group to simulate a circuit (for multi-experiments) @@ -212,6 +215,20 @@ class Executor : public Base { void gather_creg_memory(std::vector &cregs, reg_t &shot_index); #endif + + // Sample n-measurement outcomes without applying the measure operation + // to the system state + virtual std::vector sample_measure(const reg_t &qubits, uint_t shots, + RngEngine &rng) const { + std::vector ret; + return ret; + }; + virtual std::vector sample_measure(state_t &state, const reg_t &qubits, + uint_t shots, + std::vector &rng) const { + // this is for single rng, impement in sub-class for multi-shots case + return state.sample_measure(qubits, shots, rng[0]); + } }; template @@ -262,6 +279,9 @@ void Executor::set_config(const Config &config) { max_parallel_threads_ = (max_parallel_threads_ > 0) ? std::min(max_parallel_threads_, omp_threads) : std::max(1, omp_threads); + + // Set OMP threshold for state update functions + omp_qubit_threshold_ = config.statevector_parallel_threshold; #else // No OpenMP so we disable parallelization max_parallel_threads_ = 1; @@ -309,9 +329,11 @@ void Executor::set_config(const Config &config) { // set target GPUs #ifdef AER_THRUST_GPU int nDev = 0; - if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - cudaGetLastError(); - nDev = 0; + if (sim_device_ == Device::GPU) { + if (cudaGetDeviceCount(&nDev) != cudaSuccess) { + cudaGetLastError(); + nDev = 0; + } } if (config.target_gpus.has_value()) { target_gpus_ = config.target_gpus.value(); @@ -429,7 +451,6 @@ void Executor::set_parallelization(const Config &config, distributed_group_ = myrank_ / distributed_procs_; distributed_proc_bits_ = 0; - int proc_bits = 0; uint_t p = distributed_procs_; while (p > 1) { if ((p & 1) != 0) { // procs is not power of 2 @@ -451,7 +472,8 @@ void Executor::set_parallelization(const Config &config, if (max_memory_mb_ == 0) max_memory_mb_ = get_system_memory_mb(); - max_gpu_memory_mb_ = get_gpu_memory_mb(); + if (sim_device_ == Device::GPU && num_gpus_ > 0) + max_gpu_memory_mb_ = get_gpu_memory_mb(); // number of threads for parallel loop of experiments parallel_experiments_ = omp_get_num_threads(); @@ -509,11 +531,11 @@ void Executor::set_parallelization(const Config &config, // Parallel shots is > 1 // Limit parallel shots by available memory and number of shots // And assign the remaining threads to state update - int circ_memory_mb = - required_memory_mb(config, circ, noise) / num_process_per_experiment_; + int circ_memory_mb = (int)(required_memory_mb(config, circ, noise) / + num_process_per_experiment_); size_t mem_size = (sim_device_ == Device::GPU) ? max_gpu_memory_mb_ : max_memory_mb_; - if (mem_size < circ_memory_mb) + if (mem_size < (size_t)circ_memory_mb) throw std::runtime_error( "a circuit requires more memory than max_memory_mb."); // If circ memory is 0, set it to 1 so that we don't divide by zero @@ -552,7 +574,7 @@ void Executor::run_circuit(Circuit &circ, rng.set_seed(circ.seed); // Output data container - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.set_config(config); result.metadata.add(method_names_.at(method), "method"); @@ -593,7 +615,7 @@ void Executor::run_circuit(Circuit &circ, // Ideal circuit if (noise.is_ideal()) { opt_circ = circ; - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.add("ideal", "noise"); } @@ -601,7 +623,7 @@ void Executor::run_circuit(Circuit &circ, // Readout error only else if (noise.has_quantum_errors() == false) { opt_circ = noise.sample_noise(circ, rng); - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.add("readout", "noise"); } @@ -612,7 +634,7 @@ void Executor::run_circuit(Circuit &circ, // Sample noise using SuperOp method opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::superop); - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.add("superop", "noise"); } @@ -622,7 +644,7 @@ void Executor::run_circuit(Circuit &circ, noise.opset().contains(Operations::OpType::superop)) { opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::kraus); - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.add("kraus", "noise"); } @@ -630,7 +652,7 @@ void Executor::run_circuit(Circuit &circ, // General circuit noise sampling else { noise_sampling = true; - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.add("circuit", "noise"); } @@ -649,7 +671,7 @@ void Executor::run_circuit(Circuit &circ, run_circuit_shots(opt_circ, noise, config, rng, result_it, false); } } - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); // Report success result.status = ExperimentResult::Status::completed; @@ -683,7 +705,7 @@ void Executor::run_circuit(Circuit &circ, auto timer_stop = myclock_t::now(); // stop timer double time_taken = std::chrono::duration(timer_stop - timer_start).count(); - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.time_taken = time_taken; // save time also to metadata to pick time in primitive result @@ -692,7 +714,7 @@ void Executor::run_circuit(Circuit &circ, } // If an exception occurs during execution, catch it and pass it to the output catch (std::exception &e) { - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.status = ExperimentResult::Status::error; result.message = e.what(); @@ -807,30 +829,26 @@ void Executor::run_circuit_shots( std::vector cregs; reg_t shot_begin(distributed_procs_); reg_t shot_end(distributed_procs_); - for (int_t i = 0; i < distributed_procs_; i++) { + for (uint_t i = 0; i < distributed_procs_; i++) { shot_begin[i] = num_shots * i / distributed_procs_; shot_end[i] = num_shots * (i + 1) / distributed_procs_; } uint_t num_local_shots = shot_end[distributed_rank_] - shot_begin[distributed_rank_]; - int max_matrix_qubits; - auto fusion_pass = transpile_fusion(circ.opset(), config); + int max_matrix_qubits = 1; if (!sample_noise) { Noise::NoiseModel dummy_noise; state_t dummy_state; - auto fusion_pass = transpile_fusion(circ.opset(), config); ExperimentResult fusion_result; + auto fusion_pass = transpile_fusion(circ.opset(), config); fusion_pass.optimize_circuit(circ, dummy_noise, dummy_state.opset(), fusion_result); - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { ExperimentResult &result = *(result_it + i); result.metadata.copy(fusion_result.metadata); } max_matrix_qubits = get_max_matrix_qubits(circ); - } else { - max_matrix_qubits = get_max_matrix_qubits(circ); - max_matrix_qubits = std::max(max_matrix_qubits, (int)fusion_pass.max_qubit); } num_bind_params_ = circ.num_bind_params; @@ -848,9 +866,9 @@ void Executor::run_circuit_shots( init_rng, max_matrix_qubits, num_local_shots](int_t i) { state_t state; - uint_t i_shot, shot_end; + uint_t i_shot, e_shot; i_shot = num_local_shots * i / par_shots; - shot_end = num_local_shots * (i + 1) / par_shots; + e_shot = num_local_shots * (i + 1) / par_shots; auto fusion_pass = transpile_fusion(circ.opset(), config); @@ -862,7 +880,7 @@ void Executor::run_circuit_shots( state.set_distribution(this->num_process_per_experiment_); state.set_num_global_qubits(circ.num_qubits); - for (; i_shot < shot_end; i_shot++) { + for (; i_shot < e_shot; i_shot++) { RngEngine rng; uint_t shot_index = shot_begin[distributed_rank_] + i_shot; uint_t iparam = shot_index / circ.shots; @@ -883,7 +901,9 @@ void Executor::run_circuit_shots( circ_opt = noise.sample_noise(circ, rng); fusion_pass.optimize_circuit(circ_opt, dummy_noise, state.opset(), result); - state.set_max_matrix_qubits(get_max_matrix_qubits(circ_opt)); + int max_bits = get_max_matrix_qubits(circ_opt); + state.set_max_matrix_qubits( + std::max(max_bits, (int)fusion_pass.max_qubit)); } else state.set_max_matrix_qubits(max_matrix_qubits); @@ -938,11 +958,11 @@ void Executor::run_circuit_shots( num_shots = circ.shots * circ.num_bind_params; auto save_cregs = [this, &par_results, par_shots, num_shots, circ, cregs](int_t i) { - uint_t i_shot, shot_end; + uint_t i_shot, e_shot; i_shot = num_shots * i / par_shots; - shot_end = num_shots * (i + 1) / par_shots; + e_shot = num_shots * (i + 1) / par_shots; - for (; i_shot < shot_end; i_shot++) { + for (; i_shot < e_shot; i_shot++) { uint_t ip = i_shot / circ.shots; par_results[i][ip].save_count_data(cregs[i_shot], save_creg_memory_); } @@ -953,12 +973,12 @@ void Executor::run_circuit_shots( #endif for (auto &res : par_results) { - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { (result_it + i)->combine(std::move(res[i])); } } if (sim_device_ == Device::GPU) { - for (int_t i = 0; i < circ.num_bind_params; i++) { + for (uint_t i = 0; i < circ.num_bind_params; i++) { #ifdef AER_CUSTATEVEC (result_it + i)->metadata.add(cuStateVec_enable_, "cuStateVec_enable"); #endif @@ -1067,7 +1087,7 @@ void Executor::measure_sampler(InputIterator first_meas, uint_t num_registers = (register_map.empty()) ? 0ULL : 1 + register_map.rbegin()->first; ClassicalRegister creg; - for (int_t i = 0; i < all_samples.size(); i++) { + for (int_t i = all_samples.size() - 1; i >= 0; i--) { creg.initialize(num_memory, num_registers); // process memory bit measurements @@ -1283,7 +1303,7 @@ int_t Executor::get_matrix_bits(const Operations::Op &op) const { template int_t Executor::get_max_matrix_qubits(const Circuit &circ) const { int_t max_bits = 0; - int_t i; + uint_t i; if (sim_device_ != Device::CPU) { // Only applicable for GPU (and Thrust) for (i = 0; i < circ.ops.size(); i++) { @@ -1306,7 +1326,6 @@ bool Executor::has_statevector_ops(const Circuit &circ) const { template void Executor::gather_creg_memory( std::vector &cregs, reg_t &shot_index) { - int_t i, j; uint_t n64, i64, ibit, num_local_shots; if (distributed_procs_ == 0) @@ -1328,9 +1347,9 @@ void Executor::gather_creg_memory( reg_t bin_memory(n64 * num_local_shots, 0); // compress memory string to binary -#pragma omp parallel for private(i, j, i64, ibit) - for (i = 0; i < num_local_shots; i++) { - for (j = 0; j < size; j++) { +#pragma omp parallel for private(i64, ibit) + for (int_t i = 0; i < (int_t)num_local_shots; i++) { + for (int_t j = 0; j < size; j++) { i64 = j >> 6; ibit = j & 63; if (cregs[shot_index[distributed_rank_] + i].creg_memory()[j] == '1') { @@ -1343,21 +1362,22 @@ void Executor::gather_creg_memory( std::vector recv_counts(distributed_procs_); std::vector recv_offset(distributed_procs_); - for (i = 0; i < distributed_procs_ - 1; i++) { + for (uint_t i = 0; i < distributed_procs_ - 1; i++) { recv_offset[i] = shot_index[i]; recv_counts[i] = shot_index[i + 1] - shot_index[i]; } recv_offset[distributed_procs_ - 1] = shot_index[distributed_procs_ - 1]; - recv_counts[i] = cregs.size() - shot_index[distributed_procs_ - 1]; + recv_counts[distributed_procs_ - 1] = + cregs.size() - shot_index[distributed_procs_ - 1]; MPI_Allgatherv(&bin_memory[0], n64 * num_local_shots, MPI_UINT64_T, &recv[0], &recv_counts[0], &recv_offset[0], MPI_UINT64_T, distributed_comm_); // store gathered memory -#pragma omp parallel for private(i, j, i64, ibit) - for (i = 0; i < cregs.size(); i++) { - for (j = 0; j < size; j++) { +#pragma omp parallel for private(i64, ibit) + for (int_t i = 0; i < (int_t)cregs.size(); i++) { + for (int_t j = 0; j < size; j++) { i64 = j >> 6; ibit = j & 63; if (((recv[i * n64 + i64] >> ibit) & 1) == 1) diff --git a/src/simulators/density_matrix/densitymatrix.hpp b/src/simulators/density_matrix/densitymatrix.hpp index cdbc6c8336..206d458fcb 100755 --- a/src/simulators/density_matrix/densitymatrix.hpp +++ b/src/simulators/density_matrix/densitymatrix.hpp @@ -242,13 +242,13 @@ void DensityMatrix::initialize_from_vector(list_t &&vec) { template void DensityMatrix::transpose() { - const size_t rows = BaseMatrix::num_rows(); + const int_t rows = BaseMatrix::num_rows(); #pragma omp parallel for if (BaseVector::num_qubits_ > \ BaseVector::omp_threshold_ && \ BaseVector::omp_threads_ > 1) \ num_threads(BaseVector::omp_threads_) for (int_t i = 0; i < rows; i++) { - for (int_t j = i + 1; j < rows; j++) { + for (uint_t j = i + 1; j < rows; j++) { const uint_t pos_a = i * rows + j; const uint_t pos_b = j * rows + i; const auto tmp = BaseVector::data_[pos_a]; @@ -483,7 +483,7 @@ DensityMatrix::expval_pauli(const reg_t &qubits, auto lambda = [&](const int_t i, double &val_re, double &val_im) -> void { (void)val_im; // unused auto idx_vec = ((i << 1) & mask_u) | (i & mask_l); - auto idx_mat = idx_vec ^ x_mask + nrows * idx_vec; + auto idx_mat = (idx_vec ^ x_mask) + nrows * idx_vec; // Since rho is hermitian rho[i, j] + rho[j, i] = 2 real(rho[i, j]) auto val = 2 * std::real(phase * BaseVector::data_[idx_mat]); if (z_mask && (AER::Utils::popcount(idx_vec & z_mask) & 1)) { @@ -511,7 +511,7 @@ double DensityMatrix::expval_pauli_non_diagonal_chunk( auto lambda = [&](const int_t i, double &val_re, double &val_im) -> void { (void)val_im; // unused - auto idx_mat = i ^ x_mask + nrows * i; + auto idx_mat = (i ^ x_mask) + nrows * i; auto val = std::real(phase * BaseVector::data_[idx_mat]); if (z_mask && (AER::Utils::popcount(i & z_mask) & 1)) { val = -val; diff --git a/src/simulators/density_matrix/densitymatrix_executor.hpp b/src/simulators/density_matrix/densitymatrix_executor.hpp index 08708bf8ff..96429ed804 100644 --- a/src/simulators/density_matrix/densitymatrix_executor.hpp +++ b/src/simulators/density_matrix/densitymatrix_executor.hpp @@ -40,6 +40,7 @@ class Executor : public CircuitExecutor::ParallelStateExecutor, using Base = CircuitExecutor::MultiStateExecutor; using BasePar = CircuitExecutor::ParallelStateExecutor; using BaseBatch = CircuitExecutor::BatchShotsExecutor; + using Base::sample_measure; protected: public: @@ -203,14 +204,14 @@ class Executor : public CircuitExecutor::ParallelStateExecutor, //------------------------------------------------------------------------- template void Executor::initialize_qreg(uint_t num_qubits) { - for (int_t i = 0; i < Base::states_.size(); i++) { + for (uint_t i = 0; i < Base::states_.size(); i++) { Base::states_[i].qreg().set_num_qubits(BasePar::chunk_bits_); } if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { if (Base::global_state_index_ + iChunk == 0) { Base::states_[iChunk].qreg().initialize(); @@ -220,7 +221,7 @@ void Executor::initialize_qreg(uint_t num_qubits) { } } } else { - for (int_t i = 0; i < Base::states_.size(); i++) { + for (uint_t i = 0; i < Base::states_.size(); i++) { if (Base::global_state_index_ + i == 0) { Base::states_[i].qreg().initialize(); } else { @@ -236,11 +237,10 @@ void Executor::initialize_from_vector(const list_t &vec) { if ((1ull << (Base::num_qubits_ * 2)) == vec.size()) { BasePar::initialize_from_vector(vec); } else if ((1ull << (Base::num_qubits_ * 2)) == vec.size() * vec.size()) { - int_t iChunk; if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { uint_t irow_chunk = ((iChunk + Base::global_state_index_) >> ((Base::num_qubits_ - BasePar::chunk_bits_))) @@ -251,7 +251,7 @@ void Executor::initialize_from_vector(const list_t &vec) { << (BasePar::chunk_bits_); // copy part of state for this chunk - uint_t i, row, col; + uint_t i; list_t vec1(1ull << BasePar::chunk_bits_); list_t vec2(1ull << BasePar::chunk_bits_); @@ -264,7 +264,7 @@ void Executor::initialize_from_vector(const list_t &vec) { } } } else { - for (iChunk = 0; iChunk < Base::states_.size(); iChunk++) { + for (uint_t iChunk = 0; iChunk < Base::states_.size(); iChunk++) { uint_t irow_chunk = ((iChunk + Base::global_state_index_) >> ((Base::num_qubits_ - BasePar::chunk_bits_))) << (BasePar::chunk_bits_); @@ -274,7 +274,7 @@ void Executor::initialize_from_vector(const list_t &vec) { << (BasePar::chunk_bits_); // copy part of state for this chunk - uint_t i, row, col; + uint_t i; list_t vec1(1ull << BasePar::chunk_bits_); list_t vec2(1ull << BasePar::chunk_bits_); @@ -515,12 +515,12 @@ void Executor::apply_save_amplitudes_sq(const Operations::Op &op, throw std::invalid_argument( "Invalid save_amplitudes_sq instructions (empty params)."); } - const int_t size = op.int_params.size(); + const uint_t size = op.int_params.size(); rvector_t amps_sq(size); int_t iChunk; #pragma omp parallel for if (BasePar::chunk_omp_parallel_) private(iChunk) - for (iChunk = 0; iChunk < Base::states_.size(); iChunk++) { + for (iChunk = 0; iChunk < (int_t)Base::states_.size(); iChunk++) { uint_t irow, icol; irow = (Base::global_state_index_ + iChunk) >> ((Base::num_qubits_ - BasePar::chunk_bits_)); @@ -529,7 +529,7 @@ void Executor::apply_save_amplitudes_sq(const Operations::Op &op, if (irow != icol) continue; - for (int_t i = 0; i < size; ++i) { + for (uint_t i = 0; i < size; ++i) { uint_t idx = BasePar::mapped_index(op.int_params[i]); if (idx >= (irow << BasePar::chunk_bits_) && idx < ((irow + 1) << BasePar::chunk_bits_)) @@ -691,7 +691,7 @@ cmatrix_t Executor::reduced_density_matrix(const reg_t &qubits, if (qubits.empty()) { reduced_state = cmatrix_t(1, 1); std::complex sum = 0.0; - for (int_t i = 0; i < Base::states_.size(); i++) { + for (uint_t i = 0; i < Base::states_.size(); i++) { sum += Base::states_[i].qreg().trace(); } #ifdef AER_MPI @@ -719,7 +719,7 @@ template cmatrix_t Executor::reduced_density_matrix_helper(const reg_t &qubits, const reg_t &qubits_sorted) { - int_t iChunk; + uint_t iChunk; uint_t size = 1ull << (BasePar::chunk_bits_ * 2); uint_t mask = (1ull << (BasePar::chunk_bits_)) - 1; uint_t num_threads = Base::states_[0].qreg().get_omp_threads(); @@ -753,12 +753,12 @@ Executor::reduced_density_matrix_helper(const reg_t &qubits, BasePar::recv_data(tmp.data(), size, 0, iChunk); #endif #pragma omp parallel for if (num_threads > 1) num_threads(num_threads) - for (i = 0; i < size; i++) { + for (i = 0; i < (int_t)size; i++) { uint_t irow = (i >> (BasePar::chunk_bits_)) + irow_chunk; uint_t icol = (i & mask) + icol_chunk; uint_t irow_out = 0; uint_t icol_out = 0; - int j; + uint_t j; for (j = 0; j < qubits.size(); j++) { if ((irow >> qubits[j]) & 1) { irow &= ~(1ull << qubits[j]); @@ -803,7 +803,7 @@ void Executor::apply_save_density_matrix( final_op); std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -843,7 +843,7 @@ void Executor::apply_save_state(CircuitExecutor::Branch &root, std::vector copied(Base::num_bind_params_, false); if (final_op) { auto state = Base::states_[root.state_index()].move_to_matrix(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -855,7 +855,7 @@ void Executor::apply_save_state(CircuitExecutor::Branch &root, } else { auto state = Base::states_[root.state_index()].copy_to_matrix(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -878,7 +878,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, std::vector copied(Base::num_bind_params_, false); if (op.type == Operations::OpType::save_probs_ket) { // Convert to ket dict - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -890,7 +890,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, } } } else { - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -918,7 +918,7 @@ void Executor::apply_save_amplitudes(CircuitExecutor::Branch &root, Base::states_[root.state_index()].qreg().probability(op.int_params[i]); } std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -951,7 +951,7 @@ template rvector_t Executor::measure_probs(const reg_t &qubits) const { uint_t dim = 1ull << qubits.size(); rvector_t sum(dim, 0.0); - int_t i, j, k; + uint_t i, j, k; reg_t qubits_in_chunk; reg_t qubits_out_chunk; @@ -965,7 +965,7 @@ rvector_t Executor::measure_probs(const reg_t &qubits) const { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(i, j, k) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { for (i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) { uint_t irow, icol; @@ -1084,14 +1084,14 @@ template void Executor::apply_reset(const reg_t &qubits) { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { Base::states_[iChunk].qreg().apply_reset(qubits); } } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_reset(qubits); } } @@ -1120,13 +1120,13 @@ void Executor::measure_reset_update(const reg_t &qubits, mdiag[meas_state] = 1. / std::sqrt(meas_prob); if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().apply_diagonal_unitary_matrix(qubits, mdiag); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_diagonal_unitary_matrix(qubits, mdiag); } @@ -1135,13 +1135,13 @@ void Executor::measure_reset_update(const reg_t &qubits, if (qubits[0] < BasePar::chunk_bits_) { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().apply_x(qubits[0]); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_x(qubits[0]); } } else { @@ -1158,13 +1158,13 @@ void Executor::measure_reset_update(const reg_t &qubits, mdiag[meas_state] = 1. / std::sqrt(meas_prob); if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().apply_diagonal_unitary_matrix(qubits, mdiag); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_diagonal_unitary_matrix(qubits, mdiag); } @@ -1183,7 +1183,7 @@ void Executor::measure_reset_update(const reg_t &qubits, reg_t qubits_in_chunk; reg_t qubits_out_chunk; - for (int_t i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { if (qubits[i] < BasePar::chunk_bits_) { qubits_in_chunk.push_back(qubits[i]); } else { @@ -1193,18 +1193,18 @@ void Executor::measure_reset_update(const reg_t &qubits, if (qubits_in_chunk.size() > 0) { // in chunk exchange if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().apply_unitary_matrix(qubits, perm); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_unitary_matrix(qubits, perm); } } if (qubits_out_chunk.size() > 0) { // out of chunk exchange - for (int_t i = 0; i < qubits_out_chunk.size(); i++) { + for (uint_t i = 0; i < qubits_out_chunk.size(); i++) { BasePar::apply_chunk_x(qubits_out_chunk[i]); BasePar::apply_chunk_x(qubits_out_chunk[i] + (Base::num_qubits_ - BasePar::chunk_bits_)); @@ -1225,13 +1225,13 @@ std::vector Executor::sample_measure(const reg_t &qubits, rnds.push_back(rng.rand(0, 1)); reg_t allbit_samples(shots, 0); - int_t i, j; + uint_t i, j; std::vector chunkSum(Base::states_.size() + 1, 0); double sum, localSum; // calculate per chunk sum if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(i) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { for (i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) { uint_t irow, icol; @@ -1348,7 +1348,7 @@ Executor::sample_measure_with_prob(CircuitExecutor::Branch &root, uint_t nshots = root.num_shots(); reg_t shot_branch(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shot_branch[i] = root.rng_shots()[i].rand_int(probs); } @@ -1382,11 +1382,11 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, root.branches()[i]->add_op_after_branch(op); if (final_state >= 0 && final_state != i) { - Operations::Op op; - op.type = OpType::gate; - op.name = "x"; - op.qubits = qubits; - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::gate; + op2.name = "x"; + op2.qubits = qubits; + root.branches()[i]->add_op_after_branch(op2); } } } @@ -1394,7 +1394,7 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, else { // Diagonal matrix for projecting and renormalizing to measurement outcome const size_t dim = 1ULL << qubits.size(); - for (int_t i = 0; i < dim; i++) { + for (uint_t i = 0; i < dim; i++) { cvector_t mdiag(dim, 0.); mdiag[i] = 1. / std::sqrt(meas_probs[i]); @@ -1404,20 +1404,20 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, op.params = mdiag; root.branches()[i]->add_op_after_branch(op); - if (final_state >= 0 && final_state != i) { + if (final_state >= 0 && final_state != (int_t)i) { // build vectorized permutation matrix cvector_t perm(dim * dim, 0.); perm[final_state * dim + i] = 1.; perm[i * dim + final_state] = 1.; for (size_t j = 0; j < dim; j++) { - if (j != final_state && j != i) + if ((int_t)j != final_state && j != i) perm[j * dim + j] = 1.; } - Operations::Op op; - op.type = OpType::matrix; - op.qubits = qubits; - op.mats.push_back(Utils::devectorize_matrix(perm)); - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::matrix; + op2.qubits = qubits; + op2.mats.push_back(Utils::devectorize_matrix(perm)); + root.branches()[i]->add_op_after_branch(op2); } } } @@ -1430,41 +1430,23 @@ void Executor::apply_measure(CircuitExecutor::Branch &root, rvector_t probs = sample_measure_with_prob(root, qubits); // save result to cregs - for (int_t i = 0; i < probs.size(); i++) { + for (uint_t i = 0; i < probs.size(); i++) { const reg_t outcome = Utils::int2reg(i, 2, qubits.size()); root.branches()[i]->creg().store_measure(outcome, cmemory, cregister); } measure_reset_update(root, qubits, -1, probs); } -/* -template -void Executor::apply_reset(CircuitExecutor::Branch& root, const -reg_t &qubits) -{ - rvector_t probs = sample_measure_with_prob(root, qubits); - - measure_reset_update(root, qubits, 0, probs); -} -*/ template std::vector Executor::sample_measure(state_t &state, const reg_t &qubits, uint_t shots, std::vector &rng) const { - int_t i, j; + uint_t i; std::vector rnds; rnds.reserve(shots); - /* - double norm = std::real( state.qreg().trace() ); - std::cout << " trace = " << norm<::apply_kraus(const reg_t &qubits, const std::vector &kmats) { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { Base::states_[iChunk].qreg().apply_superop_matrix( qubits, Utils::vectorize_matrix(Utils::kraus_superop(kmats))); } } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_superop_matrix( qubits, Utils::vectorize_matrix(Utils::kraus_superop(kmats))); } @@ -1549,7 +1531,7 @@ template void Executor::apply_multi_chunk_swap(const reg_t &qubits) { reg_t qubits_density; - for (int_t i = 0; i < qubits.size(); i += 2) { + for (uint_t i = 0; i < qubits.size(); i += 2) { uint_t q0, q1; q0 = qubits[i * 2]; q1 = qubits[i * 2 + 1]; diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index 9041adc1dd..91637166e2 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -362,7 +362,6 @@ void State::initialize_qreg(uint_t num_qubits, densmat_t &&state) { template void State::initialize_omp() { - uint_t i; BaseState::qreg_.set_omp_threshold(omp_qubit_threshold_); if (BaseState::threads_ > 0) BaseState::qreg_.set_omp_threads( @@ -404,7 +403,6 @@ void State::set_config(const Config &config) { // Set threshold for truncating snapshots json_chop_threshold_ = config.chop_threshold; - uint_t i; BaseState::qreg_.set_json_chop_threshold(json_chop_threshold_); // Set OMP threshold for state update functions @@ -650,7 +648,7 @@ void State::apply_gate(const Operations::Op &op) { } if (qubits_out.size() > 0) { uint_t mask = 0; - for (int i = 0; i < qubits_out.size(); i++) { + for (uint_t i = 0; i < qubits_out.size(); i++) { mask |= (1ull << (qubits_out[i] - BaseState::qreg_.num_qubits())); } if ((BaseState::qreg_.chunk_index() & mask) != mask) { @@ -670,7 +668,7 @@ void State::apply_gate(const Operations::Op &op) { else if (ctrl_chunk) apply_gate_statevector(new_op); else { - for (int i = 0; i < new_op.qubits.size(); i++) + for (uint_t i = 0; i < new_op.qubits.size(); i++) new_op.qubits[i] += BaseState::qreg_.num_qubits(); apply_gate_statevector(new_op); } @@ -861,7 +859,7 @@ void State::apply_diagonal_unitary_matrix(const reg_t &qubits, if (qubits_in.size() == qubits.size()) { BaseState::qreg_.apply_diagonal_unitary_matrix(qubits, diag); } else { - for (int_t i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { if (qubits[i] >= BaseState::qreg_.num_qubits()) qubits_row[i] = qubits[i] + BaseState::num_global_qubits_ - BaseState::qreg_.num_qubits(); @@ -871,7 +869,7 @@ void State::apply_diagonal_unitary_matrix(const reg_t &qubits, diag_row); reg_t qubits_chunk(qubits_in.size() * 2); - for (int_t i = 0; i < qubits_in.size(); i++) { + for (uint_t i = 0; i < qubits_in.size(); i++) { qubits_chunk[i] = qubits_in[i]; qubits_chunk[i + qubits_in.size()] = qubits_in[i] + BaseState::qreg_.num_qubits(); diff --git a/src/simulators/density_matrix/densitymatrix_thrust.hpp b/src/simulators/density_matrix/densitymatrix_thrust.hpp index 7cbce3cd45..6de9b78aa5 100755 --- a/src/simulators/density_matrix/densitymatrix_thrust.hpp +++ b/src/simulators/density_matrix/densitymatrix_thrust.hpp @@ -38,6 +38,7 @@ class DensityMatrixThrust : public UnitaryMatrixThrust { // Parent class aliases using BaseVector = QubitVectorThrust; using BaseMatrix = UnitaryMatrixThrust; + using BaseVector::probabilities; //----------------------------------------------------------------------- // Constructors and Destructor @@ -449,9 +450,9 @@ class DensityDiagMatMult2x2 : public Chunk::GateFuncBase { template class DensityDiagMatMultNxN : public Chunk::GateFuncBase { protected: - int nqubits_; - int total_bits_; - int chunk_bits_; + uint_t nqubits_; + uint_t total_bits_; + uint_t chunk_bits_; public: DensityDiagMatMultNxN(const reg_t &qb, int total, int chunk) { @@ -541,7 +542,7 @@ class DensityMCX : public Chunk::GateFuncBase { offset_ = 1ull << qubits[qubits.size() - 1]; offset_sp_ = 1ull << (qubits[qubits.size() - 1] + chunk_qubits_); cmask_ = 0; - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) cmask_ |= (1ull << qubits[i]); enable_batch_ = batch; } @@ -629,7 +630,7 @@ class DensityMCY : public Chunk::GateFuncBase { offset_ = 1ull << qubits[qubits.size() - 1]; offset_sp_ = 1ull << (qubits[qubits.size() - 1] + chunk_qubits_); cmask_ = 0; - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) cmask_ |= (1ull << qubits[i]); enable_batch_ = batch; } @@ -1081,7 +1082,7 @@ class expval_pauli_XYZ_func_dm : public Chunk::GateFuncBase { vec = this->data_; idx_vec = ((i << 1) & mask_u_) | (i & mask_l_); - idx_mat = idx_vec ^ x_mask_ + rows_ * idx_vec; + idx_mat = (idx_vec ^ x_mask_) + rows_ * idx_vec; q0 = vec[idx_mat]; q0 = 2 * phase_ * q0; @@ -1158,7 +1159,7 @@ class expval_pauli_XYZ_func_dm_non_diagonal vec = this->data_; - idx_mat = i ^ x_mask_ + rows_ * i; + idx_mat = (i ^ x_mask_) + rows_ * i; q0 = vec[idx_mat]; q0 = phase_ * q0; @@ -1353,7 +1354,7 @@ template void DensityMatrixThrust::apply_batched_measure( const reg_t &qubits, std::vector &rng, const reg_t &cmemory, const reg_t &cregs) { - const int_t DIM = 1 << qubits.size(); + const uint_t DIM = 1 << qubits.size(); uint_t i, count = 1; if (BaseVector::enable_batch_) { if (BaseVector::chunk_.pos() != 0) { @@ -1503,7 +1504,7 @@ void DensityMatrixThrust::apply_reset(const reg_t &qubits) { auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); - for (int_t i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { qubits_sorted.push_back(qubits[i]); } BaseVector::chunk_.StoreUintParams(qubits_sorted); diff --git a/src/simulators/extended_stabilizer/chlib/chstabilizer.hpp b/src/simulators/extended_stabilizer/chlib/chstabilizer.hpp index 21f15e2c27..1d4e27fd39 100644 --- a/src/simulators/extended_stabilizer/chlib/chstabilizer.hpp +++ b/src/simulators/extended_stabilizer/chlib/chstabilizer.hpp @@ -426,8 +426,8 @@ scalar_t StabilizerState::ProposeFlip(unsigned flip_pos) { scalar_t amp; amp.e = 2 * Q.e; - amp.p = -1 * - (AER::Utils::popcount(v)); // each Hadamard gate contributes 1/sqrt(2) + // each Hadamard gate contributes 1/sqrt(2) + amp.p = -1 * (int)(AER::Utils::popcount(v)); bool isNonZero = true; for (unsigned q = 0; q < n; q++) { diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 86947f9b5a..be6a8af609 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -463,6 +463,12 @@ template void State::apply_ops_parallel(InputIterator first, InputIterator last, ExperimentResult &result, RngEngine &rng) { const int_t NUM_STATES = BaseState::qreg_.get_num_states(); + + std::vector rng_seeds(NUM_STATES); + for (int_t i = 0; i < NUM_STATES; i++) { + rng_seeds[i] = rng.rand_int(0, SIZE_MAX); + } + #pragma omp parallel for if (BaseState::qreg_.check_omp_threshold() && \ BaseState::threads_ > 1) \ num_threads(BaseState::threads_) @@ -470,10 +476,11 @@ void State::apply_ops_parallel(InputIterator first, InputIterator last, if (!BaseState::qreg_.check_eps(i)) { continue; } + RngEngine local_rng(rng_seeds[i]); for (auto it = first; it != last; it++) { switch (it->type) { case Operations::OpType::gate: - apply_gate(*it, rng, i); + apply_gate(*it, local_rng, i); break; case Operations::OpType::barrier: case Operations::OpType::qerror_loc: diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 64f734b96b..b323d95a51 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -312,6 +312,10 @@ const stringmap_t void State::initialize_qreg(uint_t num_qubits = 0) { qreg_.initialize(num_qubits); + if (BaseState::has_global_phase_) { + BaseState::qreg_.apply_diagonal_matrix( + {0}, {BaseState::global_phase_, BaseState::global_phase_}); + } } void State::initialize_omp() { @@ -725,14 +729,25 @@ void State::apply_kraus(const reg_t &qubits, void State::apply_initialize(const reg_t &qubits, const cvector_t ¶ms, RngEngine &rng) { - qreg_.apply_initialize(qubits, params, rng); + // apply global phase here + if (BaseState::has_global_phase_) { + cvector_t tmp(params.size()); + auto apply_global_phase = [&tmp, params, this](int_t i) { + tmp[i] = params[i] * BaseState::global_phase_; + }; + Utils::apply_omp_parallel_for((qubits.size() > 14), 0, params.size(), + apply_global_phase, BaseState::threads_); + qreg_.apply_initialize(qubits, tmp, rng); + } else { + qreg_.apply_initialize(qubits, params, rng); + } } void State::apply_measure(const reg_t &qubits, const reg_t &cmemory, const reg_t &cregister, RngEngine &rng) { rvector_t rands; rands.reserve(qubits.size()); - for (int_t i = 0; i < qubits.size(); ++i) + for (uint_t i = 0; i < qubits.size(); ++i) rands.push_back(rng.rand(0., 1.)); reg_t outcome = qreg_.apply_measure(qubits, rands); creg().store_measure(outcome, cmemory, cregister); @@ -766,10 +781,10 @@ State::sample_measure_using_apply_measure(const reg_t &qubits, uint_t shots, all_samples.resize(shots); std::vector rnds_list; rnds_list.reserve(shots); - for (int_t i = 0; i < shots; ++i) { + for (uint_t i = 0; i < shots; ++i) { rvector_t rands; rands.reserve(qubits.size()); - for (int_t j = 0; j < qubits.size(); ++j) + for (uint_t j = 0; j < qubits.size(); ++j) rands.push_back(rng.rand(0., 1.)); rnds_list.push_back(rands); } diff --git a/src/simulators/matrix_product_state/matrix_product_state_size_estimator.hpp b/src/simulators/matrix_product_state/matrix_product_state_size_estimator.hpp index 600b29207d..d243cc8ba6 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_size_estimator.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_size_estimator.hpp @@ -53,7 +53,7 @@ void MPSSizeEstimator::initialize(uint_t nq) { qubit_map_.resize(nq); qubit_order_.resize(nq); - for (int_t i = 0; i < nq; i++) { + for (uint_t i = 0; i < nq; i++) { tensor_size_[i].first = 1; tensor_size_[i].second = 1; @@ -66,7 +66,7 @@ void MPSSizeEstimator::initialize(uint_t nq) { uint_t MPSSizeEstimator::estimate(const std::vector &ops) { uint_t n = ops.size(); - for (int_t i = 0; i < n; i++) { + for (uint_t i = 0; i < n; i++) { switch (ops[i].type) { case Operations::OpType::gate: case Operations::OpType::matrix: @@ -79,7 +79,7 @@ uint_t MPSSizeEstimator::estimate(const std::vector &ops) { } } uint_t max_bond = 0; - for (int_t i = 0; i < num_qubits_ - 1; i++) { + for (uint_t i = 0; i < num_qubits_ - 1; i++) { if (max_bond < bond_dimensions_[i]) max_bond = bond_dimensions_[i]; } @@ -89,16 +89,16 @@ uint_t MPSSizeEstimator::estimate(const std::vector &ops) { void MPSSizeEstimator::apply_qubits(const reg_t &qubits) { reg_t sorted(qubits.size()); - for (int_t i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { sorted[i] = qubit_map_[qubits[i]]; } std::sort(sorted.begin(), sorted.end()); - for (int_t i = 1; i < qubits.size(); i++) { + for (uint_t i = 1; i < qubits.size(); i++) { reorder_qubit(sorted[i - 1], sorted[i]); } - for (int_t i = 0; i < qubits.size() - 1; i++) { + for (uint_t i = 0; i < qubits.size() - 1; i++) { update(sorted[i]); } } diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 27e533c702..a420e9e9d3 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -139,14 +139,6 @@ class MultiStateExecutor : public Executor { void measure_sampler(InputIterator first_meas, InputIterator last_meas, Branch &branch, ResultItr result_it); - // sampling measure - virtual std::vector sample_measure(state_t &state, const reg_t &qubits, - uint_t shots, - std::vector &rng) const { - // this is for single rng, impement in sub-class for multi-shots case - return state.sample_measure(qubits, shots, rng[0]); - } - void apply_save_expval(Branch &root, const Operations::Op &op, ResultItr result); }; @@ -192,7 +184,7 @@ void MultiStateExecutor::set_distribution(uint_t num_states) { state_index_begin_.resize(Base::distributed_procs_); state_index_end_.resize(Base::distributed_procs_); - for (int_t i = 0; i < Base::distributed_procs_; i++) { + for (uint_t i = 0; i < Base::distributed_procs_; i++) { state_index_begin_[i] = num_global_states_ * i / Base::distributed_procs_; state_index_end_[i] = num_global_states_ * (i + 1) / Base::distributed_procs_; @@ -212,7 +204,7 @@ void MultiStateExecutor::set_parallelization( template bool MultiStateExecutor::allocate_states(uint_t num_shots, const Config &config) { - int_t i; + uint_t i; bool ret = true; states_.resize(num_shots); @@ -281,12 +273,11 @@ void MultiStateExecutor::run_circuit_shots( Noise::NoiseModel dummy_noise; state_t dummy_state; - RngEngine dummy_rng; - dummy_rng.set_seed(circ.seed); // this is not used actually Circuit circ_opt; if (sample_noise) { RngEngine dummy_rng; + dummy_rng.set_seed(circ.seed); circ_opt = noise.sample_noise(circ, dummy_rng, Noise::NoiseModel::Method::circuit, true); auto fusion_pass = Base::transpile_fusion(circ_opt.opset(), config); @@ -385,12 +376,12 @@ void MultiStateExecutor::run_circuit_shots( #endif for (auto &res : par_results) { - for (int_t i = 0; i < Base::num_bind_params_; i++) { + for (uint_t i = 0; i < Base::num_bind_params_; i++) { (result_it + i)->combine(std::move(res[i])); } } - for (int_t i = 0; i < Base::num_bind_params_; i++) { + for (uint_t i = 0; i < Base::num_bind_params_; i++) { (result_it + i)->metadata.add(true, "shot_branching_enabled"); (result_it + i) ->metadata.add(sample_noise, "runtime_noise_sampling_enabled"); @@ -413,7 +404,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( bool can_sample = false; OpItr measure_seq = last; OpItr it = last - 1; - int_t num_measure = 0; + uint_t num_measure = 0; if (shot_branching_sampling_enable_) { do { @@ -445,14 +436,14 @@ void MultiStateExecutor::run_circuit_with_shot_branching( if (Base::num_bind_params_ > 1) { if (par_shots > 1) { #pragma omp parallel for num_threads(par_shots) - for (int_t i = 0; i < nshots; i++) { + for (int_t i = 0; i < (int_t)nshots; i++) { uint_t gid = global_state_index_ + ishot + i; uint_t ip = gid / Base::num_shots_per_bind_param_; shots_storage[i].set_seed(circ.seed_for_params[ip] + (gid % Base::num_shots_per_bind_param_)); } } else { - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { uint_t gid = global_state_index_ + ishot + i; uint_t ip = gid / Base::num_shots_per_bind_param_; shots_storage[i].set_seed(circ.seed_for_params[ip] + @@ -466,10 +457,10 @@ void MultiStateExecutor::run_circuit_with_shot_branching( shots_storage[0].set_seed(circ.seed + global_state_index_ + ishot); if (par_shots > 1) { #pragma omp parallel for num_threads(par_shots) - for (int_t i = 1; i < nshots; i++) + for (int_t i = 1; i < (int_t)nshots; i++) shots_storage[i].set_seed(circ.seed + global_state_index_ + ishot + i); } else { - for (int_t i = 1; i < nshots; i++) + for (uint_t i = 1; i < nshots; i++) shots_storage[i].set_seed(circ.seed + global_state_index_ + ishot + i); } } @@ -498,7 +489,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( uint_t num_active_states = 1; // set branches - for (int_t i = 0; i < waiting_branches.size(); i++) { + for (uint_t i = 0; i < waiting_branches.size(); i++) { if (i > num_states) break; uint_t sid = top_state + i; @@ -547,9 +538,9 @@ void MultiStateExecutor::run_circuit_with_shot_branching( if (branches[istate]->num_branches() > 0) { // if there are additional ops remaining, queue them on new // branches - for (int_t k = iadd + 1; + for (uint_t k = iadd + 1; k < branches[istate]->additional_ops().size(); k++) { - for (int_t l = 0; l < branches[istate]->num_branches(); + for (uint_t l = 0; l < branches[istate]->num_branches(); l++) branches[istate]->branches()[l]->add_op_after_branch( branches[istate]->additional_ops()[k]); @@ -631,10 +622,10 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // repeat until new branch is available if (nbranch > 0) { uint_t num_states_prev = branches.size(); - for (int_t i = 0; i < num_states_prev; i++) { + for (uint_t i = 0; i < num_states_prev; i++) { // add new branches if (branches[i]->num_branches() > 0) { - for (int_t j = 0; j < branches[i]->num_branches(); j++) { + for (uint_t j = 0; j < branches[i]->num_branches(); j++) { if (branches[i]->branches()[j]->num_shots() > 0) { // add new branched state uint_t pos = branches.size(); @@ -680,7 +671,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // check if there are remaining ops num_active_states = 0; - for (int_t i = 0; i < branches.size(); i++) { + for (uint_t i = 0; i < branches.size(); i++) { if (branches[i]->op_iterator() != measure_seq || branches[i]->additional_ops().size() > 0) num_active_states++; @@ -707,7 +698,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( Utils::apply_omp_parallel_for(can_parallel, 0, par_shots, sampling_measure_func, par_shots); - for (int_t i = 0; i < Base::num_bind_params_; i++) + for (uint_t i = 0; i < Base::num_bind_params_; i++) (result_it + i)->metadata.add(true, "shot_branching_sampling_enabled"); } else { // save cregs to result @@ -718,7 +709,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( for (; istate < state_end; istate++) { if (Base::num_process_per_experiment_ > 1) { - for (int_t j = 0; j < branches[istate]->num_shots(); j++) { + for (uint_t j = 0; j < branches[istate]->num_shots(); j++) { uint_t idx = branches[istate]->rng_shots()[j].initial_seed(); uint_t ip = branches[istate]->param_index(j); idx += ip * Base::num_shots_per_bind_param_; @@ -728,13 +719,13 @@ void MultiStateExecutor::run_circuit_with_shot_branching( } else { std::string memory_hex = states_[branches[istate]->state_index()].creg().memory_hex(); - for (int_t j = 0; j < branches[istate]->num_shots(); j++) { + for (uint_t j = 0; j < branches[istate]->num_shots(); j++) { uint_t ip = branches[istate]->param_index(j); par_results[i][ip].data.add_accum(static_cast(1ULL), "counts", memory_hex); } if (Base::save_creg_memory_) { - for (int_t j = 0; j < branches[istate]->num_shots(); j++) { + for (uint_t j = 0; j < branches[istate]->num_shots(); j++) { uint_t ip = branches[istate]->param_index(j); par_results[i][ip].data.add_list(memory_hex, "memory"); } @@ -748,14 +739,14 @@ void MultiStateExecutor::run_circuit_with_shot_branching( } // clear - for (int_t i = 0; i < branches.size(); i++) { + for (uint_t i = 0; i < branches.size(); i++) { branches[i].reset(); } branches.clear(); } for (auto &res : par_results) { - for (int_t i = 0; i < Base::num_bind_params_; i++) { + for (uint_t i = 0; i < Base::num_bind_params_; i++) { (result_it + i)->combine(std::move(res[i])); } } @@ -777,7 +768,7 @@ void MultiStateExecutor::apply_runtime_parameterization( root.branch_shots_by_params(); // add binded op after branch - for (int_t i = 0; i < nparams; i++) { + for (uint_t i = 0; i < nparams; i++) { uint_t ip = root.branches()[i]->param_index(0); Operations::Op bind_op = Operations::bind_parameter(op, ip, Base::num_bind_params_); @@ -799,7 +790,7 @@ void MultiStateExecutor::measure_sampler(InputIterator first_meas, // Check if meas_circ is empty, and if so return initial creg if (first_meas == last_meas) { if (Base::num_process_per_experiment_ > 1) { - for (int_t i = 0; i < shots; i++) { + for (uint_t i = 0; i < shots; i++) { uint_t idx = branch.rng_shots()[i].initial_seed(); uint_t ip = branch.param_index(i); idx += ip * Base::num_shots_per_bind_param_; @@ -807,7 +798,7 @@ void MultiStateExecutor::measure_sampler(InputIterator first_meas, cregs_[idx] = state.creg(); } } else { - for (int_t i = 0; i < shots; i++) { + for (uint_t i = 0; i < shots; i++) { uint_t ip = branch.param_index(i); (result + ip)->save_count_data(state.creg(), Base::save_creg_memory_); } @@ -837,7 +828,7 @@ void MultiStateExecutor::measure_sampler(InputIterator first_meas, // Generate the samples std::vector all_samples; - all_samples = sample_measure(state, meas_qubits, shots, rng); + all_samples = this->sample_measure(state, meas_qubits, shots, rng); // Make qubit map of position in vector of measured qubits std::unordered_map qubit_map; @@ -859,11 +850,7 @@ void MultiStateExecutor::measure_sampler(InputIterator first_meas, } // Process samples - uint_t num_memory = - (memory_map.empty()) ? 0ULL : 1 + memory_map.rbegin()->first; - uint_t num_registers = - (register_map.empty()) ? 0ULL : 1 + register_map.rbegin()->first; - for (int_t i = 0; i < all_samples.size(); i++) { + for (int_t i = all_samples.size() - 1; i >= 0; i--) { ClassicalRegister creg = state.creg(); // process memory bit measurements @@ -929,7 +916,7 @@ void MultiStateExecutor::apply_save_expval(Branch &root, std::vector expval_var(2); expval_var[0] = expval; // mean expval_var[1] = sq_expval - expval * expval; // variance - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -940,7 +927,7 @@ void MultiStateExecutor::apply_save_expval(Branch &root, } } } else { - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) diff --git a/src/simulators/parallel_state_executor.hpp b/src/simulators/parallel_state_executor.hpp index 85121689a9..7cb26bc735 100644 --- a/src/simulators/parallel_state_executor.hpp +++ b/src/simulators/parallel_state_executor.hpp @@ -136,14 +136,6 @@ class ParallelStateExecutor : public virtual MultiStateExecutor { // Apply a save expectation value instruction void apply_save_expval(const Operations::Op &op, ExperimentResult &result); - // Sample n-measurement outcomes without applying the measure operation - // to the system state - virtual std::vector sample_measure(const reg_t &qubits, uint_t shots, - RngEngine &rng) const { - std::vector ret; - return ret; - }; - // swap between chunks virtual void apply_chunk_swap(const reg_t &qubits); @@ -270,7 +262,7 @@ ParallelStateExecutor::transpile_cache_blocking( template bool ParallelStateExecutor::allocate(uint_t num_qubits, const Config &config) { - int_t i; + uint_t i; Base::num_qubits_ = num_qubits; chunk_bits_ = cache_block_qubit_; @@ -312,9 +304,9 @@ bool ParallelStateExecutor::allocate(uint_t num_qubits, template bool ParallelStateExecutor::allocate_states(uint_t num_states, const Config &config) { - int_t i; + uint_t i; bool init_states = true; - uint_t num_states_allocated; + uint_t num_states_allocated = num_states; // deallocate qregs before reallocation if (Base::states_.size() > 0) { if (Base::states_.size() == num_states) @@ -532,7 +524,7 @@ void ParallelStateExecutor::run_circuit_shots( result.metadata.copy(fusion_result.metadata); } - for (int_t ishot = 0; ishot < circ.shots; ishot++) { + for (uint_t ishot = 0; ishot < circ.shots; ishot++) { RngEngine rng; if (iparam == 0 && ishot == 0) rng = init_rng; @@ -616,7 +608,7 @@ void ParallelStateExecutor::measure_sampler(InputIterator first_meas, // Generate the samples auto timer_start = myclock_t::now(); - auto all_samples = sample_measure(meas_qubits, shots, rng); + auto all_samples = this->sample_measure(meas_qubits, shots, rng); auto time_taken = std::chrono::duration(myclock_t::now() - timer_start).count(); result.metadata.add(time_taken, "sample_measure_time"); @@ -792,11 +784,11 @@ void ParallelStateExecutor::apply_ops_chunks( uint_t iOpBegin = iOp + 1; if (Base::num_groups_ > 1 && chunk_omp_parallel_) { #pragma omp parallel for num_threads(Base::num_groups_) - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) apply_cache_blocking_ops(ig, first + iOpBegin, first + iOpEnd, result, rng, iparam); } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (uint_t ig = 0; ig < Base::num_groups_; ig++) apply_cache_blocking_ops(ig, first + iOpBegin, first + iOpEnd, result, rng, iparam); } @@ -810,11 +802,11 @@ void ParallelStateExecutor::apply_ops_chunks( final_ops && nOp == iOp + 1)) { if (Base::num_groups_ > 1 && chunk_omp_parallel_) { #pragma omp parallel for num_threads(Base::num_groups_) - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) apply_cache_blocking_ops(ig, bind_op.cbegin(), bind_op.cend(), result, rng, iparam); } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (uint_t ig = 0; ig < Base::num_groups_; ig++) apply_cache_blocking_ops(ig, bind_op.cbegin(), bind_op.cend(), result, rng, iparam); } @@ -824,11 +816,11 @@ void ParallelStateExecutor::apply_ops_chunks( final_ops && nOp == iOp + 1)) { if (Base::num_groups_ > 1 && chunk_omp_parallel_) { #pragma omp parallel for num_threads(Base::num_groups_) - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) apply_cache_blocking_ops(ig, first + iOp, first + iOp + 1, result, rng, iparam); } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (uint_t ig = 0; ig < Base::num_groups_; ig++) apply_cache_blocking_ops(ig, first + iOp, first + iOp + 1, result, rng, iparam); } @@ -843,10 +835,10 @@ void ParallelStateExecutor::apply_ops_chunks( if (Base::num_groups_ > 1 && chunk_omp_parallel_) { #pragma omp parallel for num_threads(Base::num_groups_) - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) Base::states_[Base::top_state_of_group_[ig]].qreg().synchronize(); } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) + for (uint_t ig = 0; ig < Base::num_groups_; ig++) Base::states_[Base::top_state_of_group_[ig]].qreg().synchronize(); } @@ -881,7 +873,7 @@ void ParallelStateExecutor::apply_cache_blocking_ops( const int_t iGroup, InputIterator first, InputIterator last, ExperimentResult &result, RngEngine &rng, uint_t iparam) { // for each chunk in group - for (int_t iChunk = Base::top_state_of_group_[iGroup]; + for (uint_t iChunk = Base::top_state_of_group_[iGroup]; iChunk < Base::top_state_of_group_[iGroup + 1]; iChunk++) { // fecth chunk in cache if (Base::states_[iChunk].qreg().fetch_chunk()) { @@ -901,15 +893,15 @@ void ParallelStateExecutor::apply_cache_blocking_ops( template template void ParallelStateExecutor::initialize_from_vector(const list_t &vec) { - int_t iChunk; + uint_t iChunk; if (chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(iChunk) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { for (iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { list_t tmp(1ull << (chunk_bits_ * qubit_scale())); - for (int_t i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { + for (uint_t i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { tmp[i] = vec[((Base::global_state_index_ + iChunk) << (chunk_bits_ * qubit_scale())) + i]; @@ -920,7 +912,7 @@ void ParallelStateExecutor::initialize_from_vector(const list_t &vec) { } else { for (iChunk = 0; iChunk < Base::num_local_states_; iChunk++) { list_t tmp(1ull << (chunk_bits_ * qubit_scale())); - for (int_t i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { + for (uint_t i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { tmp[i] = vec[((Base::global_state_index_ + iChunk) << (chunk_bits_ * qubit_scale())) + i]; @@ -933,10 +925,10 @@ void ParallelStateExecutor::initialize_from_vector(const list_t &vec) { template template void ParallelStateExecutor::initialize_from_matrix(const list_t &mat) { - int_t iChunk; + uint_t iChunk; if (chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(iChunk) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { for (iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { list_t tmp(1ull << (chunk_bits_), 1ull << (chunk_bits_)); @@ -949,7 +941,7 @@ void ParallelStateExecutor::initialize_from_matrix(const list_t &mat) { << (chunk_bits_); // copy part of state for this chunk - uint_t i, row, col; + uint_t i; for (i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { uint_t icol = i & ((1ull << chunk_bits_) - 1); uint_t irow = i >> chunk_bits_; @@ -970,7 +962,7 @@ void ParallelStateExecutor::initialize_from_matrix(const list_t &mat) { << (chunk_bits_); // copy part of state for this chunk - uint_t i, row, col; + uint_t i; for (i = 0; i < (1ull << (chunk_bits_ * qubit_scale())); i++) { uint_t icol = i & ((1ull << chunk_bits_) - 1); uint_t irow = i >> chunk_bits_; @@ -985,7 +977,7 @@ void ParallelStateExecutor::initialize_from_matrix(const list_t &mat) { template auto ParallelStateExecutor::apply_to_matrix(bool copy) { // this function is used to collect states over chunks - int_t iChunk; + uint_t iChunk; uint_t size = 1ull << (chunk_bits_ * qubit_scale()); uint_t mask = (1ull << (chunk_bits_)) - 1; uint_t num_threads = Base::states_[0].qreg().get_omp_threads(); @@ -1024,7 +1016,7 @@ auto ParallelStateExecutor::apply_to_matrix(bool copy) { recv_data(tmp.data(), size, 0, iChunk); #endif #pragma omp parallel for if (num_threads > 1) num_threads(num_threads) - for (i = 0; i < size; i++) { + for (i = 0; i < (int_t)size; i++) { uint_t irow = i >> (chunk_bits_); uint_t icol = i & mask; uint_t idx = @@ -1093,9 +1085,7 @@ void ParallelStateExecutor::apply_save_expval( template void ParallelStateExecutor::apply_chunk_swap(const reg_t &qubits) { - uint_t nLarge = 1; uint_t q0, q1; - int_t iChunk; q0 = qubits[qubits.size() - 2]; q1 = qubits[qubits.size() - 1]; @@ -1112,14 +1102,14 @@ void ParallelStateExecutor::apply_chunk_swap(const reg_t &qubits) { // inside chunk if (chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for num_threads(Base::num_groups_) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_mcswap(qubits); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_mcswap(qubits); } @@ -1139,7 +1129,7 @@ void ParallelStateExecutor::apply_chunk_swap(const reg_t &qubits) { // processes // is needed auto apply_chunk_swap_1qubit = [this, mask1, qubits](int_t iGroup) { - for (int_t ic = Base::top_state_of_group_[iGroup]; + for (uint_t ic = Base::top_state_of_group_[iGroup]; ic < Base::top_state_of_group_[iGroup + 1]; ic++) { uint_t baseChunk; baseChunk = ic & (~mask1); @@ -1150,7 +1140,7 @@ void ParallelStateExecutor::apply_chunk_swap(const reg_t &qubits) { }; auto apply_chunk_swap_2qubits = [this, mask0, mask1, qubits](int_t iGroup) { - for (int_t ic = Base::top_state_of_group_[iGroup]; + for (uint_t ic = Base::top_state_of_group_[iGroup]; ic < Base::top_state_of_group_[iGroup + 1]; ic++) { uint_t baseChunk; baseChunk = ic & (~(mask0 | mask1)); @@ -1172,7 +1162,8 @@ void ParallelStateExecutor::apply_chunk_swap(const reg_t &qubits) { } #ifdef AER_MPI else { - int_t iPair; + uint_t nLarge = 1; + uint_t iPair; uint_t nPair; uint_t baseChunk, iChunk1, iChunk2; @@ -1343,14 +1334,14 @@ void ParallelStateExecutor::apply_multi_chunk_swap( // swap inside chunks to prepare for all-to-all shuffle if (chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_multi_swaps(local_swaps); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_multi_swaps(local_swaps); } @@ -1366,7 +1357,7 @@ void ParallelStateExecutor::apply_multi_chunk_swap( for (uint_t i = 0; i < nchunk; i++) { chunk_offset[i] = 0; - for (uint_t k = 0; k < nswap; k++) { + for (int_t k = 0; k < nswap; k++) { if (((i >> k) & 1) != 0) chunk_offset[i] += (1ull << chunk_shuffle_qubits[k]); } @@ -1381,7 +1372,7 @@ void ParallelStateExecutor::apply_multi_chunk_swap( uint_t i1, i2, k, ii, t; baseChunk = 0; ii = iPair; - for (k = 0; k < nswap; k++) { + for (k = 0; k < (uint_t)nswap; k++) { t = ii & ((1ull << chunk_shuffle_qubits_sorted[k]) - 1); baseChunk += t; ii = (ii - t) << 1; @@ -1395,7 +1386,6 @@ void ParallelStateExecutor::apply_multi_chunk_swap( // all-to-all // send data for (uint_t iswap = 1; iswap < nchunk; iswap++) { - uint_t sizeRecv, sizeSend; uint_t num_local_swap = 0; for (i1 = 0; i1 < nchunk; i1++) { i2 = i1 ^ iswap; @@ -1412,6 +1402,7 @@ void ParallelStateExecutor::apply_multi_chunk_swap( continue; // swap while data is exchanged between processes } #ifdef AER_MPI + uint_t sizeRecv, sizeSend; uint_t offset1 = i1 << (chunk_bits_ * qubit_scale() - nswap); uint_t offset2 = i2 << (chunk_bits_ * qubit_scale() - nswap); uint_t iChunk1 = @@ -1419,7 +1410,7 @@ void ParallelStateExecutor::apply_multi_chunk_swap( uint_t iChunk2 = baseChunk + chunk_offset[i2] - Base::global_state_index_; - int_t tid = (iPair << nswap) + iswap; + uint_t tid = (iPair << nswap) + iswap; if (iProc1 == Base::distributed_rank_) { auto pRecv = Base::states_[iChunk1].qreg().recv_buffer(sizeRecv); @@ -1499,14 +1490,14 @@ void ParallelStateExecutor::apply_multi_chunk_swap( // restore qubits order if (chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_multi_swaps(local_swaps); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_multi_swaps(local_swaps); } @@ -1515,13 +1506,10 @@ void ParallelStateExecutor::apply_multi_chunk_swap( template void ParallelStateExecutor::apply_chunk_x(const uint_t qubit) { - int_t iChunk; - uint_t nLarge = 1; - if (qubit < chunk_bits_ * qubit_scale()) { auto apply_mcx = [this, qubit](int_t ig) { reg_t qubits(1, qubit); - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) Base::states_[iChunk].qreg().apply_mcx(qubits); }; @@ -1529,9 +1517,7 @@ void ParallelStateExecutor::apply_chunk_x(const uint_t qubit) { (chunk_omp_parallel_ && Base::num_groups_ > 1), 0, Base::num_groups_, apply_mcx); } else { // exchange over chunks - int_t iPair; uint_t nPair, mask; - uint_t baseChunk, iChunk1, iChunk2; reg_t qubits(2); qubits[0] = qubit; qubits[1] = qubit; @@ -1547,7 +1533,7 @@ void ParallelStateExecutor::apply_chunk_x(const uint_t qubit) { nPair = Base::num_local_states_ >> 1; auto apply_chunk_swap = [this, mask, qubits](int_t iGroup) { - for (int_t ic = Base::top_state_of_group_[iGroup]; + for (uint_t ic = Base::top_state_of_group_[iGroup]; ic < Base::top_state_of_group_[iGroup + 1]; ic++) { uint_t pairChunk; pairChunk = ic ^ mask; @@ -1562,6 +1548,9 @@ void ParallelStateExecutor::apply_chunk_x(const uint_t qubit) { } #ifdef AER_MPI else { + uint_t iPair; + uint_t baseChunk, iChunk1, iChunk2; + // chunk scheduler that supports any number of processes uint_t nu[3]; uint_t ub[3]; @@ -1570,7 +1559,6 @@ void ParallelStateExecutor::apply_chunk_x(const uint_t qubit) { uint_t iLocalChunk, iRemoteChunk, iProc; int i; - nLarge = 1; nu[0] = 1ull << (qubit - chunk_bits_ * qubit_scale()); ub[0] = 0; iu[0] = 0; @@ -1864,8 +1852,8 @@ void ParallelStateExecutor::gather_state( AER::Vector> &state) { #ifdef AER_MPI if (Base::distributed_procs_ > 1) { - uint_t size, local_size, global_size, offset; - int i; + uint_t global_size; + uint_t i; std::vector recv_counts(Base::distributed_procs_); std::vector recv_offset(Base::distributed_procs_); diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index e9d1eb5811..0d81f707a4 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -83,7 +83,7 @@ class Branch { void set_shots(std::vector &shots) { shots_ = shots; } void initialize_shots(const uint_t nshots, const uint_t seed) { shots_.resize(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shots_[i].set_seed(seed + i); } } @@ -151,7 +151,7 @@ class Branch { if (param_index_.size() == 1) { return param_index_[0]; } - for (int_t i = 0; i < param_index_.size(); i++) { + for (uint_t i = 0; i < param_index_.size(); i++) { if (param_shots_[i] > ishot) { return param_index_[i]; } @@ -174,13 +174,13 @@ void Branch::branch_shots(reg_t &shots, int_t nbranch) { if (param_index_.size() > 1) { branches_[i]->param_index_ = param_index_; branches_[i]->param_shots_.resize(param_index_.size()); - for (int_t j = 0; j < param_index_.size(); j++) + for (uint_t j = 0; j < param_index_.size(); j++) branches_[i]->param_shots_[j] = 0; } } uint_t pos = 0; - for (int_t i = 0; i < shots.size(); i++) { + for (uint_t i = 0; i < shots.size(); i++) { branches_[shots[i]]->shots_.push_back(shots_[i]); if (param_index_.size() > 1) { @@ -193,19 +193,19 @@ void Branch::branch_shots(reg_t &shots, int_t nbranch) { // set parameter indices if (param_index_.size() > 1) { for (int_t i = 0; i < nbranch; i++) { - uint_t pos = 0; - while (pos < branches_[i]->param_index_.size()) { - if (branches_[i]->param_shots_[pos] == 0) { + uint_t ppos = 0; + while (ppos < branches_[i]->param_index_.size()) { + if (branches_[i]->param_shots_[ppos] == 0) { branches_[i]->param_index_.erase(branches_[i]->param_index_.begin() + - pos); + ppos); branches_[i]->param_shots_.erase(branches_[i]->param_index_.begin() + - pos); + ppos); } else { - if (pos > 0) { - branches_[i]->param_shots_[pos] += - branches_[i]->param_shots_[pos - 1]; + if (ppos > 0) { + branches_[i]->param_shots_[ppos] += + branches_[i]->param_shots_[ppos - 1]; } - pos++; + ppos++; } } } @@ -218,27 +218,27 @@ void Branch::branch_shots(reg_t &shots, int_t nbranch) { void Branch::branch_shots_by_params(void) { branches_.resize(param_index_.size()); - for (int_t i = 0; i < param_index_.size(); i++) { + for (uint_t i = 0; i < param_index_.size(); i++) { branches_[i] = std::make_shared(); branches_[i]->creg_ = creg_; branches_[i]->iter_ = iter_; branches_[i]->flow_marks_ = flow_marks_; } uint_t pos = 0; - for (int_t i = 0; i < shots_.size(); i++) { + for (uint_t i = 0; i < shots_.size(); i++) { if (i >= param_shots_[pos]) pos++; branches_[pos]->shots_.push_back(shots_[i]); } - for (int_t i = 0; i < param_index_.size(); i++) { + for (uint_t i = 0; i < param_index_.size(); i++) { branches_[i]->set_param_index(param_index_[i], 0); } } void Branch::advance_iterator(void) { iter_++; - for (int_t i = 0; i < branches_.size(); i++) { + for (uint_t i = 0; i < branches_.size(); i++) { branches_[i]->iter_++; } } @@ -253,24 +253,24 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, reg_t shot_map(nshots); std::vector> noises; - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { std::vector noise_ops = noise.sample_noise_loc(op, shots_[i]); // search same noise ops int_t pos = -1; - for (int_t j = 0; j < noises.size(); j++) { + for (uint_t j = 0; j < noises.size(); j++) { if (noise_ops.size() != noises[j].size()) continue; bool same = true; - for (int_t k = 0; k < noise_ops.size(); k++) { + for (uint_t k = 0; k < noise_ops.size(); k++) { if (noise_ops[k].type != noises[j][k].type || noise_ops[k].name != noises[j][k].name) same = false; else if (noise_ops[k].qubits.size() != noises[j][k].qubits.size()) same = false; else { - for (int_t l = 0; l < noise_ops[k].qubits.size(); l++) { + for (uint_t l = 0; l < noise_ops[k].qubits.size(); l++) { if (noise_ops[k].qubits[l] != noises[j][k].qubits[l]) { same = false; break; @@ -286,7 +286,7 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, } else if (noise_ops[k].params.size() != noises[j][k].params.size()) same = false; else { - for (int_t l = 0; l < noise_ops[k].params.size(); l++) { + for (uint_t l = 0; l < noise_ops[k].params.size(); l++) { if (noise_ops[k].params[l] != noises[j][k].params[l]) { same = false; break; @@ -298,12 +298,12 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, if (noise_ops[k].mats.size() != noises[j][k].mats.size()) same = false; else { - for (int_t l = 0; l < noise_ops[k].mats.size(); l++) { + for (uint_t l = 0; l < noise_ops[k].mats.size(); l++) { if (noise_ops[k].mats[l].size() != noises[j][k].mats[l].size()) { same = false; break; } - for (int_t m = 0; m < noise_ops[k].mats[l].size(); m++) { + for (uint_t m = 0; m < noise_ops[k].mats[l].size(); m++) { if (noise_ops[k].mats[l][m] != noises[j][k].mats[l][m]) { same = false; break; @@ -333,7 +333,7 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, creg_ = creg; branch_shots(shot_map, noises.size()); - for (int_t i = 0; i < noises.size(); i++) { + for (uint_t i = 0; i < noises.size(); i++) { branches_[i]->copy_ops_after_branch(noises[i]); } @@ -342,7 +342,7 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, void Branch::remove_empty_branches(void) { int_t istart = 0; - for (int_t j = 0; j < branches_.size(); j++) { + for (uint_t j = 0; j < branches_.size(); j++) { if (branches_[j]->num_shots() > 0) { // copy shots to the root shots_ = branches_[j]->rng_shots(); @@ -359,7 +359,7 @@ void Branch::remove_empty_branches(void) { std::vector> new_branches; - for (int_t j = istart; j < branches_.size(); j++) { + for (uint_t j = istart; j < branches_.size(); j++) { if (branches_[j]->num_shots() > 0) new_branches.push_back(branches_[j]); else @@ -370,7 +370,7 @@ void Branch::remove_empty_branches(void) { void Branch::reset_branch(void) { // reset random seeds - for (int_t i = 0; i < shots_.size(); i++) { + for (uint_t i = 0; i < shots_.size(); i++) { shots_[i].set_seed(shots_[i].initial_seed()); } additional_ops_.clear(); @@ -390,7 +390,7 @@ void Branch::set_param_index(uint_t ishot, uint_t nshots_per_param) { param_shots_.clear(); param_index_.push_back(ishot / nshots_per_param); - for (int_t i = 1; i < shots_.size(); i++) { + for (uint_t i = 1; i < shots_.size(); i++) { uint_t ip = (ishot + i) / nshots_per_param; if (ip != param_index_[pos]) { param_shots_.push_back(i); diff --git a/src/simulators/stabilizer/clifford.hpp b/src/simulators/stabilizer/clifford.hpp index 1de95089ce..568413d810 100644 --- a/src/simulators/stabilizer/clifford.hpp +++ b/src/simulators/stabilizer/clifford.hpp @@ -431,7 +431,7 @@ bool Clifford::measure_and_update(const uint64_t qubit, auto measure_non_determinisitic_func = [this, rS, row, qubit](AER::int_t i) { uint64_t row_mask = ~0ull; - if ((row >> destabilizer_phases_.BLOCK_BITS) == i) + if ((row >> destabilizer_phases_.BLOCK_BITS) == (uint_t)i) row_mask ^= (1ull << (row & destabilizer_phases_.BLOCK_MASK)); uint64_t d_mask = row_mask & destabilizer_table_[qubit].X(i); diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index 26ab0f418e..1a2df3410e 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -255,7 +255,7 @@ void State::set_config(const Config &config) { } bool State::validate_parameters(const std::vector &ops) const { - for (int_t i = 0; i < ops.size(); i++) { + for (uint_t i = 0; i < ops.size(); i++) { if (ops[i].type == OpType::gate) { // check parameter of R gates if (ops[i].name == "rx" || ops[i].name == "ry" || ops[i].name == "rz") { @@ -417,16 +417,14 @@ void State::apply_gate(const Operations::Op &op) { case Gates::ry: pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3; if (pi2 == 1) { - // HX - BaseState::qreg_.append_x(op.qubits[0]); BaseState::qreg_.append_h(op.qubits[0]); + BaseState::qreg_.append_x(op.qubits[0]); } else if (pi2 == 2) { // Y BaseState::qreg_.append_y(op.qubits[0]); } else if (pi2 == 3) { - // Hdg - BaseState::qreg_.append_h(op.qubits[0]); BaseState::qreg_.append_x(op.qubits[0]); + BaseState::qreg_.append_h(op.qubits[0]); } break; case Gates::rz: @@ -641,7 +639,7 @@ template void State::get_probabilities_auxiliary(const reg_t &qubits, std::string outcome, double outcome_prob, T &probs) { - uint_t qubit_for_branching = -1; + int_t qubit_for_branching = -1; for (uint_t i = 0; i < qubits.size(); ++i) { uint_t qubit = qubits[qubits.size() - i - 1]; if (outcome[i] == 'X') { @@ -692,7 +690,7 @@ void State::get_probability_helper(const reg_t &qubits, const std::string &outcome, std::string &outcome_carry, double &prob_carry) { - uint_t qubit_for_branching = -1; + int_t qubit_for_branching = -1; for (uint_t i = 0; i < qubits.size(); ++i) { uint_t qubit = qubits[qubits.size() - i - 1]; if (outcome_carry[i] == 'X') { diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index d0cd4baac0..ee5613328a 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -207,6 +207,8 @@ class Base { // Set a complex global phase value exp(1j * theta) for the state void set_global_phase(double theta); + bool has_global_phase() { return has_global_phase_; } + complex_t global_phase() { return global_phase_; } // Set a complex global phase value exp(1j * theta) for the state void add_global_phase(double theta); diff --git a/src/simulators/statevector/chunk/chunk_container.hpp b/src/simulators/statevector/chunk/chunk_container.hpp index b249b12c95..50900d3bf8 100644 --- a/src/simulators/statevector/chunk/chunk_container.hpp +++ b/src/simulators/statevector/chunk/chunk_container.hpp @@ -395,7 +395,7 @@ void ChunkContainer::UnmapBuffer(Chunk &buf) { template void ChunkContainer::unmap_all(void) { - int_t i; + uint_t i; for (i = 0; i < chunks_map_.size(); i++) chunks_map_[i] = false; num_chunk_mapped_ = 0; @@ -804,14 +804,8 @@ void ChunkContainer::ExecuteSum2(double *pSum, Function func, #endif } -void host_func_launcher(void *pParam) { - HostFuncBase *func = reinterpret_cast(pParam); - func->execute(); -} - template void ChunkContainer::allocate_chunks(void) { - uint_t i; chunks_map_.resize(num_chunks_, false); reduced_queue_begin_.resize(num_chunks_, 0); @@ -855,7 +849,7 @@ void ChunkContainer::apply_matrix( #else if (N <= 10) { #endif - int i; + uint_t i; for (i = 0; i < N; i++) { qubits_sorted.push_back(qubits[i]); } @@ -918,7 +912,7 @@ void ChunkContainer::apply_batched_matrix( } else { auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); - for (int i = 0; i < N; i++) { + for (uint_t i = 0; i < N; i++) { qubits_sorted.push_back(qubits[i]); } StoreUintParams(qubits_sorted, iChunk); @@ -971,8 +965,8 @@ void ChunkContainer::apply_phase(const uint_t iChunk, const int_t control_bits, const std::complex phase, const uint_t gid, const uint_t count) { - Execute(phase_func(qubits, *(thrust::complex *)&phase), - iChunk, gid, count); + thrust::complex p(phase); + Execute(phase_func(qubits, p), iChunk, gid, count); } template @@ -989,8 +983,8 @@ void ChunkContainer::apply_multi_swaps(const uint_t iChunk, const uint_t gid, const uint_t count) { // max 5 swaps can be applied at once using GPU's shared memory - for (int_t i = 0; i < qubits.size(); i += 10) { - int_t n = 10; + for (uint_t i = 0; i < qubits.size(); i += 10) { + uint_t n = 10; if (i + n > qubits.size()) n = qubits.size() - i; @@ -1009,7 +1003,6 @@ void ChunkContainer::apply_permutation( const uint_t iChunk, const reg_t &qubits, const std::vector> &pairs, const uint_t gid, const uint_t count) { - const size_t N = qubits.size(); auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); @@ -1080,7 +1073,7 @@ void ChunkContainer::probabilities(std::vector &probs, template double ChunkContainer::norm(uint_t iChunk, uint_t count) const { - double ret; + double ret = 0.0; ExecuteSum(&ret, norm_func(), iChunk, count); return ret; @@ -1089,7 +1082,7 @@ double ChunkContainer::norm(uint_t iChunk, uint_t count) const { template double ChunkContainer::trace(uint_t iChunk, uint_t row, uint_t count) const { - double ret; + double ret = 0.0; ExecuteSum(&ret, trace_func(row), iChunk, count); return ret; @@ -1108,7 +1101,7 @@ double ChunkContainer::expval_matrix(const uint_t iChunk, else { auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); - for (int_t i = 0; i < N; i++) { + for (uint_t i = 0; i < N; i++) { qubits_sorted.push_back(qubits[i]); } @@ -1166,7 +1159,6 @@ void ChunkContainer::batched_expval_pauli( count, first); return; } - double ret; // specialize x_max == 0 if (x_mask == 0) { ExecuteSum2(nullptr, diff --git a/src/simulators/statevector/chunk/chunk_manager.hpp b/src/simulators/statevector/chunk/chunk_manager.hpp index cb3c7ebbb9..2e304515c6 100644 --- a/src/simulators/statevector/chunk/chunk_manager.hpp +++ b/src/simulators/statevector/chunk/chunk_manager.hpp @@ -35,11 +35,11 @@ class ChunkManager { std::vector>> chunks_; // chunk containers for each device and host - int num_devices_; // number of devices - int num_places_; // number of places (devices + host) + uint_t num_devices_; // number of devices + uint_t num_places_; // number of places (devices + host) - int chunk_bits_; // number of qubits of chunk - int num_qubits_; // number of global qubits + uint_t chunk_bits_; // number of qubits of chunk + uint_t num_qubits_; // number of global qubits uint_t num_chunks_; // number of chunks on this process uint_t chunk_index_; // global chunk index for the first chunk @@ -105,7 +105,6 @@ class ChunkManager { template ChunkManager::ChunkManager() { - int i, j; num_places_ = 1; chunk_bits_ = 0; num_chunks_ = 0; @@ -126,7 +125,9 @@ ChunkManager::ChunkManager() { #else #ifdef AER_THRUST_GPU - if (cudaGetDeviceCount(&num_devices_) == cudaSuccess) { + int ndev; + if (cudaGetDeviceCount(&ndev) == cudaSuccess) { + num_devices_ = ndev; num_places_ = num_devices_; } else { cudaGetLastError(); @@ -168,19 +169,21 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, bool density_mat, reg_t &gpus, bool enable_cuStatevec) { uint_t num_buffers; - int iDev; + uint_t iDev; uint_t is, ie, nc; - int i; + uint_t i; char *str; - bool multi_gpu = false; - bool hybrid = false; + bool hybrid = false; +#ifdef AER_THRUST_GPU + bool multi_gpu = false; //--- for test str = getenv("AER_MULTI_GPU"); if (str) { multi_gpu = true; num_places_ = num_devices_; } +#endif str = getenv("AER_HYBRID"); if (str) { hybrid = true; @@ -192,8 +195,10 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, target_gpus_ = gpus; if (target_gpus_.size() > 0) { num_devices_ = target_gpus_.size(); +#ifdef AER_THRUST_GPU if (num_devices_ > 1) multi_gpu = true; +#endif } else { target_gpus_.resize(num_devices_); for (iDev = 0; iDev < num_devices_; iDev++) { @@ -203,7 +208,7 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, chunk_index_ = chunk_index; - if (num_qubits_ != nqubits || chunk_bits_ != chunk_bits || + if (num_qubits_ != (uint_t)nqubits || chunk_bits_ != (uint_t)chunk_bits || nchunks > num_chunks_) { // free previous allocation Free(); @@ -224,7 +229,6 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, multi_shots_ = true; #ifdef AER_THRUST_CPU - multi_gpu = false; num_places_ = 1; #else if (chunk_distribution_enable_) { @@ -260,7 +264,9 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, #endif } else { // single chunk num_buffers = 0; +#ifdef AER_THRUST_GPU multi_gpu = false; +#endif num_places_ = 1; num_chunks_ = nchunks; multi_shots_ = false; @@ -346,7 +352,7 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, } } if (chunks_allocated < num_chunks_) { - int nplaces_add = num_places_; + uint_t nplaces_add = num_places_; if ((num_chunks_ - chunks_allocated) < nplaces_add) nplaces_add = (num_chunks_ - chunks_allocated); // rest of chunks are stored on host @@ -391,7 +397,7 @@ uint_t ChunkManager::Allocate(int chunk_bits, int nqubits, template void ChunkManager::Free(void) { - int i; + uint_t i; for (i = 0; i < chunks_.size(); i++) { chunks_[i]->Deallocate(); @@ -408,7 +414,7 @@ void ChunkManager::Free(void) { template bool ChunkManager::MapChunk(Chunk &chunk, int iplace) { - int i; + uint_t i; for (i = 0; i < num_places_; i++) { if (chunks_[(iplace + i) % num_places_]->MapChunk(chunk)) { @@ -422,7 +428,7 @@ bool ChunkManager::MapChunk(Chunk &chunk, int iplace) { template bool ChunkManager::MapBufferChunk(Chunk &out, int idev) { if (idev < 0) { - int i; + uint_t i; for (i = 0; i < num_devices_; i++) { if (chunks_[i]->MapBufferChunk(out)) break; diff --git a/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp b/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp index e72d72003d..4baad583da 100644 --- a/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp +++ b/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp @@ -377,9 +377,6 @@ void cuStateVecChunkContainer::apply_diagonal_matrix( qubits32[i] = qubits[i]; int32_t *pQubits = &qubits32[control_bits]; - int32_t *pControl = nullptr; - if (control_bits > 0) - pControl = &qubits32[0]; uint_t bits; uint_t nc; @@ -686,7 +683,6 @@ void cuStateVecChunkContainer::apply_rotation( const uint_t iChunk, const reg_t &qubits, const Rotation r, const double theta, const uint_t gid, const uint_t count) { custatevecPauli_t pauli[2]; - int nPauli = 1; BaseContainer::set_device(); @@ -705,25 +701,21 @@ void cuStateVecChunkContainer::apply_rotation( case Rotation::xx: pauli[0] = CUSTATEVEC_PAULI_X; pauli[1] = CUSTATEVEC_PAULI_X; - nPauli = 2; control_bits--; break; case Rotation::yy: pauli[0] = CUSTATEVEC_PAULI_Y; pauli[1] = CUSTATEVEC_PAULI_Y; - nPauli = 2; control_bits--; break; case Rotation::zz: pauli[0] = CUSTATEVEC_PAULI_Z; pauli[1] = CUSTATEVEC_PAULI_Z; - nPauli = 2; control_bits--; break; case Rotation::zx: pauli[0] = CUSTATEVEC_PAULI_Z; pauli[1] = CUSTATEVEC_PAULI_X; - nPauli = 2; control_bits--; break; default: @@ -911,7 +903,7 @@ double cuStateVecChunkContainer::expval_pauli( const custatevecPauli_t *pauliOperatorsArray[] = {pauliOps}; const int32_t *basisBitsArray[] = {qubits32}; double ret[1]; - const uint32_t nBasisBitsArray[] = {qubits.size()}; + const uint32_t nBasisBitsArray[] = {(uint32_t)qubits.size()}; custatevecStatus_t err; err = custatevecComputeExpectationsOnPauliBasis( diff --git a/src/simulators/statevector/chunk/device_chunk_container.hpp b/src/simulators/statevector/chunk/device_chunk_container.hpp index 6ae28ae79d..d78f0ebd01 100644 --- a/src/simulators/statevector/chunk/device_chunk_container.hpp +++ b/src/simulators/statevector/chunk/device_chunk_container.hpp @@ -220,7 +220,7 @@ class DeviceChunkContainer : public ChunkContainer { void allocate_creg(uint_t num_mem, uint_t num_reg); int measured_cbit(uint_t iChunk, int qubit) { uint_t n64, i64, ibit; - if (qubit >= this->num_creg_bits_) + if ((uint_t)qubit >= this->num_creg_bits_) return -1; n64 = (this->num_creg_bits_ + 63) >> 6; i64 = qubit >> 6; @@ -324,7 +324,6 @@ uint_t DeviceChunkContainer::Allocate(int idev, int chunk_bits, bool density_matrix) { uint_t nc = chunks; uint_t i; - int mat_bits; this->chunk_bits_ = chunk_bits; this->num_qubits_ = num_qubits; @@ -359,13 +358,10 @@ uint_t DeviceChunkContainer::Allocate(int idev, int chunk_bits, if (multi_shots) { // mult-shot parallelization for small qubits multi_shots_ = true; - mat_bits = AER_DEFAULT_MATRIX_BITS; nc = chunks; num_matrices_ = chunks; } else { multi_shots_ = false; - - mat_bits = AER_DEFAULT_MATRIX_BITS; num_matrices_ = 1; nc = chunks; } @@ -519,7 +515,7 @@ void DeviceChunkContainer::calculate_matrix_buffer_size(int bits, if (shots > AER_MAX_SAMPLING_SHOTS) shots = AER_MAX_SAMPLING_SHOTS; uint_t b = this->matrix_bits_; - while ((1ull << (b * 2)) < shots) { + while ((1ull << (b * 2)) < (uint_t)shots) { b++; } this->matrix_bits_ = b; @@ -545,7 +541,7 @@ void DeviceChunkContainer::calculate_matrix_buffer_size(int bits, } params_buffer_size_ = size; - if (shots > 1 && params_buffer_size_ < shots) { + if (shots > 1 && params_buffer_size_ < (uint_t)shots) { params_buffer_size_ = shots; } } @@ -553,10 +549,9 @@ void DeviceChunkContainer::calculate_matrix_buffer_size(int bits, template void DeviceChunkContainer::ResizeMatrixBuffers(int bits, int max_shots) { - uint_t size; uint_t n = num_matrices_ + this->num_buffers_; - if (bits != this->matrix_bits_) { + if ((uint_t)bits != this->matrix_bits_) { calculate_matrix_buffer_size(bits, max_shots); } @@ -941,7 +936,7 @@ void DeviceChunkContainer::set_blocked_qubits(uint_t iChunk, auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); - int i; + uint_t i; for (i = 0; i < qubits.size(); i++) { blocked_qubits_holder_[iBlock * QV_MAX_REGISTERS + i] = qubits_sorted[i]; } @@ -1010,8 +1005,7 @@ void DeviceChunkContainer::queue_blocked_gate( } cvector_t mat(4, 0.0); - int i; - uint_t idx, idxParam, iBlock; + uint_t iBlock; if (iChunk >= this->num_chunks_) { // for buffer chunks iBlock = num_matrices_ + iChunk - this->num_chunks_; } else { @@ -1028,7 +1022,7 @@ void DeviceChunkContainer::queue_blocked_gate( params.mask_ = mask; params.gate_ = gate; params.qubit_ = 0; - for (i = 0; i < num_blocked_qubits_[iBlock]; i++) { + for (uint_t i = 0; i < num_blocked_qubits_[iBlock]; i++) { if (blocked_qubits_holder_[iBlock * QV_MAX_REGISTERS + i] == qubit) { params.qubit_ = i; break; @@ -1408,8 +1402,8 @@ void DeviceChunkContainer::copy_reduce_buffer(std::vector &ret, count * reduce_buffer_size_, tmp.begin()); #endif - for (int_t i = 0; i < count; i++) { - for (int_t j = 0; j < num_val; j++) + for (uint_t i = 0; i < count; i++) { + for (uint_t j = 0; j < num_val; j++) ret[i * num_val + j] = tmp[i * reduce_buffer_size_ + j]; } } diff --git a/src/simulators/statevector/chunk/host_chunk_container.hpp b/src/simulators/statevector/chunk/host_chunk_container.hpp index e901086d45..696ad6478d 100644 --- a/src/simulators/statevector/chunk/host_chunk_container.hpp +++ b/src/simulators/statevector/chunk/host_chunk_container.hpp @@ -121,7 +121,6 @@ uint_t HostChunkContainer::Allocate(int idev, int chunk_bits, int matrix_bit, int max_shots, bool density_matrix) { uint_t nc = chunks; - uint_t i; ChunkContainer::chunk_bits_ = chunk_bits; ChunkContainer::num_qubits_ = num_qubits; diff --git a/src/simulators/statevector/chunk/thrust_kernels.hpp b/src/simulators/statevector/chunk/thrust_kernels.hpp index 70f9c36134..1d08973f7a 100644 --- a/src/simulators/statevector/chunk/thrust_kernels.hpp +++ b/src/simulators/statevector/chunk/thrust_kernels.hpp @@ -69,7 +69,10 @@ class GateFuncBase { public: GateFuncBase() { data_ = NULL; + matrix_ = NULL; + params_ = NULL; base_index_ = 0; + chunk_bits_ = 0; cregs_ = NULL; num_creg_bits_ = 0; conditional_bit_ = -1; @@ -147,7 +150,7 @@ class GateFuncBase { template class GateFuncWithCache : public GateFuncBase { protected: - int nqubits_; + uint_t nqubits_; public: GateFuncWithCache(uint_t nq) { nqubits_ = nq; } @@ -210,7 +213,7 @@ class GateFuncWithCache : public GateFuncBase { template class GateFuncSumWithCache : public GateFuncBase { protected: - int nqubits_; + uint_t nqubits_; public: GateFuncSumWithCache(uint_t nq) { nqubits_ = nq; } @@ -276,7 +279,7 @@ class strided_range { : public thrust::unary_function { difference_type stride; - stride_functor(difference_type stride) : stride(stride) {} + stride_functor(difference_type _stride) : stride(_stride) {} __host__ __device__ difference_type operator()(const difference_type &i) const { @@ -301,8 +304,8 @@ class strided_range { typedef PermutationIterator iterator; // construct strided_range for the range [first,last) - strided_range(Iterator first, Iterator last, difference_type stride) - : first(first), last(last), stride(stride) {} + strided_range(Iterator _first, Iterator _last, difference_type _stride) + : first(_first), last(_last), stride(_stride) {} iterator begin(void) const { return PermutationIterator( @@ -409,7 +412,7 @@ class initialize_component_1qubit_func : public GateFuncBase { template class initialize_component_func : public GateFuncBase { protected: - int nqubits; + uint_t nqubits; uint_t offset; uint_t mat_pos; uint_t mat_num; @@ -825,7 +828,7 @@ class MatrixMult16x16 : public GateFuncBase { int qubits_count(void) { return 4; } __host__ __device__ void operator()(const uint_t &i) const { - uint_t i0, i1, i2, i3, i4, offset, f0, f1, f2; + uint_t i0, i1, i2, i3, i4, offset; thrust::complex *vec; thrust::complex q0, q1, q2, q3, q4, q5, q6, q7; thrust::complex q8, q9, q10, q11, q12, q13, q14, q15; @@ -865,9 +868,6 @@ class MatrixMult16x16 : public GateFuncBase { q15 = vec[i0 + offset3 + offset2 + offset1 + offset0]; offset = 0; - f0 = 0; - f1 = 0; - f2 = 0; for (j = 0; j < 16; j++) { r = pMat[0 + j] * q0; r += pMat[16 + j] * q1; @@ -936,9 +936,9 @@ class MatrixMultNxN : public GateFuncWithCache { template class MatrixMultNxN_LU : public GateFuncBase { protected: - int nqubits; + uint_t nqubits; uint_t matSize; - int nswap; + uint_t nswap; public: MatrixMultNxN_LU(const cvector_t &mat, const reg_t &qb, @@ -978,7 +978,7 @@ class MatrixMultNxN_LU : public GateFuncBase { params[nqubits + i] = j; } - if (dmax != 0) { + if (dmax > 0) { c0 = matLU[(i << nqubits) + params[nqubits + i]]; for (j = i + 1; j < matSize; j++) { @@ -1211,7 +1211,7 @@ class BatchedMatrixMult2x2 : public GateFuncBase { public: BatchedMatrixMult2x2(const reg_t &qubits, uint_t imat, uint_t nshots_per_mat) { - int i; + uint_t i; nqubits_ = qubits.size(); offset_ = 1ull << qubits[nqubits_ - 1]; @@ -1402,7 +1402,7 @@ class DiagonalMult4x4 : public GateFuncBase { template class DiagonalMultNxN : public GateFuncBase { protected: - int nqubits; + uint_t nqubits; public: DiagonalMultNxN(const reg_t &qb) { nqubits = qb.size(); } @@ -1504,7 +1504,7 @@ class BatchedDiagonalMatrixMult2x2 : public GateFuncBase { public: BatchedDiagonalMatrixMult2x2(const reg_t &qubits, uint_t imat, uint_t nshots_per_mat) { - int i; + uint_t i; nqubits_ = qubits.size(); mask_ = (1ull << qubits[nqubits_ - 1]); @@ -1557,7 +1557,6 @@ class BatchedDiagonalMatrixMultNxN : public GateFuncBase { public: BatchedDiagonalMatrixMultNxN(const uint_t nq, uint_t imat, uint_t nshots_per_mat) { - int i; nqubits_ = nq; matrix_begin_ = imat; @@ -1894,9 +1893,8 @@ class CSwapChunk_func : public GateFuncBase { CSwapChunk_func(const reg_t &qubits, uint_t block_bits, thrust::complex *pVec0, thrust::complex *pVec1, bool wb) { - int i; - int nqubits; - int qubit_t; + uint_t nqubits; + uint_t qubit_t; nqubits = qubits.size(); if (qubits[nqubits - 2] < qubits[nqubits - 1]) { @@ -2078,10 +2076,8 @@ class NormMatrixMultNxN : public GateFuncSumWithCache { thrust::complex q, r; thrust::complex m; uint_t mat_size, irow; - thrust::complex *vec; thrust::complex *pMat; - vec = this->data_; pMat = this->matrix_; mat_size = 1ull << this->nqubits_; @@ -2492,7 +2488,7 @@ class batched_expval_I_func : public GateFuncBase { operator()(const uint_t &i) const { thrust::complex q; thrust::complex *vec; - double d, dv; + double d, dv = 0.0; vec = this->data_; q = vec[i]; @@ -2529,7 +2525,7 @@ class batched_expval_pauli_Z_func : public GateFuncBase { operator()(const uint_t &i) const { thrust::complex *vec; thrust::complex q0; - double d, dv; + double d, dv = 0.0; vec = this->data_; @@ -2585,7 +2581,7 @@ class batched_expval_pauli_XYZ_func : public GateFuncBase { thrust::complex q1; thrust::complex q0p; thrust::complex q1p; - double d0, d1, ret, ret_v; + double d0, d1, ret, ret_v = 0.0; uint_t idx0, idx1; vec = this->data_; diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index 4039c7c5f3..94753f409b 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -955,7 +955,9 @@ void QubitVector::allocate_mem(size_t data_size) { if (data_ == nullptr) { #if !defined(_WIN64) && !defined(_WIN32) void *data = nullptr; - posix_memalign(&data, 64, sizeof(std::complex) * data_size); + if (posix_memalign(&data, 64, sizeof(std::complex) * data_size) != + 0) + throw std::runtime_error("Cannot allocate memory by posix_memalign"); data_ = reinterpret_cast *>(data); #else data_ = reinterpret_cast *>( @@ -969,7 +971,8 @@ void QubitVector::allocate_checkpoint(size_t data_size) { free_checkpoint(); #if !defined(_WIN64) && !defined(_WIN32) void *data = nullptr; - posix_memalign(&data, 64, sizeof(std::complex) * data_size); + if (posix_memalign(&data, 64, sizeof(std::complex) * data_size) != 0) + throw std::runtime_error("Cannot allocate memory by posix_memalign"); checkpoint_ = reinterpret_cast *>(data); #else checkpoint_ = reinterpret_cast *>( @@ -1765,13 +1768,13 @@ void QubitVector::apply_chunk_swap(const reg_t &qubits, if (write_back) { #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (int_t k = 0; k < data_size_; ++k) { + for (int_t k = 0; k < (int_t)data_size_; ++k) { std::swap(data_[k], src.data_[k]); } } else { #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (int_t k = 0; k < data_size_; ++k) { + for (int_t k = 0; k < (int_t)data_size_; ++k) { data_[k] = src.data_[k]; } } @@ -1803,7 +1806,7 @@ void QubitVector::apply_chunk_swap(const reg_t &qubits, if (q0 >= num_qubits_) { // exchange whole of chunk each other #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (int_t k = 0; k < data_size_; ++k) { + for (int_t k = 0; k < (int_t)data_size_; ++k) { data_[k] = recv_buffer_[k]; } } else { @@ -1824,13 +1827,13 @@ void QubitVector::apply_chunk_swap(QubitVector &src, if (src.chunk_index_ == chunk_index_) { #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (int_t k = 0; k < size; ++k) { + for (int_t k = 0; k < (int_t)size; ++k) { data_[dest_offset + k] = src.recv_buffer_[src_offset + k]; } } else { #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (int_t k = 0; k < size; ++k) { + for (int_t k = 0; k < (int_t)size; ++k) { std::swap(data_[dest_offset + k], src.data_[src_offset + k]); } } @@ -1838,8 +1841,8 @@ void QubitVector::apply_chunk_swap(QubitVector &src, template void QubitVector::apply_multi_swaps(const reg_t &qubits) { - for (int_t i = 0; i < qubits.size(); i += 10) { - int_t n = 10; + for (uint_t i = 0; i < qubits.size(); i += 10) { + uint_t n = 10; if (i + n > qubits.size()) n = qubits.size() - i; @@ -1850,17 +1853,17 @@ void QubitVector::apply_multi_swaps(const reg_t &qubits) { auto lambda = [&](const indexes_t &inds) -> void { cvector_t cache(size); - for (int_t i = 0; i < size; i++) - cache[i] = data_[inds[i]]; + for (uint_t ii = 0; ii < size; ii++) + cache[ii] = data_[inds[ii]]; - for (int_t i = 0; i < size; i++) { - uint_t pos = i; - for (int_t j = 0; j < nq; j += 2) { + for (uint_t ii = 0; ii < size; ii++) { + uint_t pos = ii; + for (uint_t j = 0; j < nq; j += 2) { if ((((pos >> j) & 1) ^ ((pos >> (j + 1)) & 1)) != 0) { pos ^= ((1ull << j) | (1ull << (j + 1))); } } - data_[inds[i]] = cache[pos]; + data_[inds[ii]] = cache[pos]; } }; apply_lambda(lambda, qubits_swap); diff --git a/src/simulators/statevector/qubitvector_thrust.hpp b/src/simulators/statevector/qubitvector_thrust.hpp index da96761fc0..36bb5a9837 100644 --- a/src/simulators/statevector/qubitvector_thrust.hpp +++ b/src/simulators/statevector/qubitvector_thrust.hpp @@ -819,17 +819,17 @@ void QubitVectorThrust::initialize_component( std::sort(qubits_sorted.begin(), qubits_sorted.end()); auto qubits_param = qubits; - int i; + uint_t i; for (i = 0; i < qubits.size(); i++) qubits_param.push_back(qubits_sorted[i]); - int nbit = chunk_.container()->matrix_bits(); + uint_t nbit = chunk_.container()->matrix_bits(); if (nbit > qubits.size()) nbit = qubits.size(); uint_t dim = 1ull << qubits.size(); uint_t sub_dim = 1ull << nbit; - for (uint_t i = 0; i < dim; i += sub_dim) { + for (i = 0; i < dim; i += sub_dim) { cvector_t state(sub_dim); for (uint_t j = 0; j < sub_dim; j++) state[j] = state0[dim - sub_dim - i + j]; @@ -872,7 +872,7 @@ uint_t QubitVectorThrust::chunk_setup(int chunk_bits, int num_qubits, if (chunk_manager_->chunk_bits() == chunk_bits && chunk_manager_->num_qubits() == num_qubits) { - bool mapped = chunk_manager_->MapChunk(chunk_, 0); + chunk_manager_->MapChunk(chunk_, 0); chunk_.set_chunk_index(chunk_index_); return num_local_chunks; } @@ -903,8 +903,8 @@ uint_t QubitVectorThrust::chunk_setup(int chunk_bits, int num_qubits, recv_chunk_.unmap(); // mapping/setting chunk - bool mapped = chunk_manager_->MapChunk(chunk_, 0); chunk_.set_chunk_index(chunk_index_); + chunk_manager_->MapChunk(chunk_, 0); return num_chunks_allocated; } @@ -932,7 +932,7 @@ QubitVectorThrust::chunk_setup(const QubitVectorThrust &base, // mapping/setting chunk chunk_manager_ = base.chunk_manager_; - bool mapped = chunk_manager_->MapChunk(chunk_, 0); + chunk_manager_->MapChunk(chunk_, 0); return 0; } @@ -1260,7 +1260,7 @@ void QubitVectorThrust::initialize_from_vector(const list_t &statevec) { int_t i; #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) \ num_threads(omp_threads_) - for (i = 0; i < data_size_; i++) { + for (i = 0; i < (int_t)data_size_; i++) { tmp[i] = statevec[i]; } initialize_from_data(&tmp[0], tmp.size()); @@ -1322,7 +1322,7 @@ void QubitVectorThrust::initialize_creg( if (chunk_.pos() == 0) { chunk_.container()->allocate_creg(num_cmem_bits_, num_creg_bits_); - int_t i; + uint_t i; for (i = 0; i < num_register; i++) { if (register_hex[register_hex.size() - 1 - i] == '0') { store_cregister(i, 0); @@ -1528,7 +1528,6 @@ void QubitVectorThrust::apply_multiplexer( for (const auto &q : control_qubits) { qubits.push_back(q); } - size_t N = qubits.size(); cvector_t matMP(DIM * DIM, 0.0); uint_t b, i, j; @@ -1627,7 +1626,7 @@ void QubitVectorThrust::apply_mcx(const reg_t &qubits) { return; if (register_blocking_) { - int i; + uint_t i; uint_t mask = 0; for (i = 0; i < qubits.size() - 1; i++) { mask |= (1ull << qubits[i]); @@ -1645,7 +1644,7 @@ void QubitVectorThrust::apply_mcy(const reg_t &qubits) { return; if (register_blocking_) { - int i; + uint_t i; uint_t mask = 0; for (i = 0; i < qubits.size() - 1; i++) { mask |= (1ull << qubits[i]); @@ -1678,7 +1677,7 @@ template void QubitVectorThrust::apply_chunk_swap(const reg_t &qubits, QubitVectorThrust &src, bool write_back) { - int q0, q1, t; + uint_t q0, q1, t; q0 = qubits[0]; q1 = qubits[1]; @@ -1759,7 +1758,7 @@ void QubitVectorThrust::apply_chunk_swap(const reg_t &qubits, template void QubitVectorThrust::apply_chunk_swap(const reg_t &qubits, uint_t remote_chunk_index) { - int q0, q1, t; + uint_t q0, q1, t; q0 = qubits[qubits.size() - 2]; q1 = qubits[qubits.size() - 1]; @@ -1840,7 +1839,7 @@ void QubitVectorThrust::apply_mcphase( return; if (register_blocking_) { - int i; + uint_t i; uint_t mask = 0; for (i = 0; i < qubits.size() - 1; i++) { mask |= (1ull << qubits[i]); @@ -1875,7 +1874,7 @@ void QubitVectorThrust::apply_mcu(const reg_t &qubits, return; } else { if (register_blocking_) { - int i; + uint_t i; uint_t mask = 0; for (i = 0; i < qubits.size() - 1; i++) { mask |= (1ull << qubits[i]); @@ -1897,7 +1896,7 @@ void QubitVectorThrust::apply_mcu(const reg_t &qubits, return; } else { if (register_blocking_) { - int i; + uint_t i; uint_t mask = 0; for (i = 0; i < qubits.size() - 1; i++) { mask |= (1ull << qubits[i]); @@ -2252,7 +2251,7 @@ template void QubitVectorThrust::apply_batched_measure( const reg_t &qubits, std::vector &rng, const reg_t &cmemory, const reg_t &cregs) { - const int_t DIM = 1 << qubits.size(); + const uint_t DIM = 1 << qubits.size(); uint_t i, count = 1; if (enable_batch_) { if (chunk_.pos() != 0) { @@ -2386,7 +2385,7 @@ class reset_func : public Chunk::GateFuncBase { template void QubitVectorThrust::apply_batched_reset( const reg_t &qubits, std::vector &rng) { - const int_t DIM = 1 << qubits.size(); + const uint_t DIM = 1 << qubits.size(); uint_t i, count = 1; if (enable_batch_) { if (chunk_.pos() != 0) { @@ -2547,7 +2546,6 @@ class set_batched_creg_func : public Chunk::GateFuncBase { uint_t *mask; uint_t val = 1; n64 = (this->num_creg_bits_ + 63) >> 6; - int j; mask = this->params_; @@ -2686,7 +2684,7 @@ void QubitVectorThrust::batched_expval_pauli( std::vector &val, const reg_t &qubits, const std::string &pauli, bool variance, std::complex param, bool last, const complex_t initial_phase) const { - uint_t i, count = 1; + uint_t count = 1; if (enable_batch_) { if (chunk_.pos() != 0) { return; // first chunk execute all in batch @@ -2898,12 +2896,11 @@ void QubitVectorThrust::apply_batched_pauli_ops( } uint_t count = ops.size(); int num_inner_threads = omp_get_max_threads() / num_threads_per_group_; - int_t i; reg_t params(4 * count); auto count_paulis = [this, ¶ms, ops](int_t i) { - int_t j; + uint_t j; uint_t x_max = 0; uint_t num_y = 0; uint_t x_mask = 0; @@ -2975,7 +2972,6 @@ class MatrixMult2x2_conditional : public Chunk::GateFuncBase { thrust::complex q0, q1; thrust::complex *vec0; thrust::complex *vec1; - double p, p0, p1, rnd; uint_t iChunk = i >> this->chunk_bits_; double scale = @@ -3012,7 +3008,7 @@ class MatrixMultNxN_conditional : public Chunk::GateFuncWithCache { __host__ __device__ void run_with_cache(uint_t _tid, uint_t _idx, thrust::complex *_cache) const { - uint_t j, threadID; + uint_t j; thrust::complex q, r; thrust::complex m; uint_t mat_size, irow; @@ -3066,7 +3062,6 @@ class check_kraus_probability_func : public Chunk::GateFuncBase { __host__ __device__ void operator()(const uint_t &i) const { uint_t iChunk = i; double p0, p1, rnd; - bool mult = false; p0 = reduce_[iChunk * reduce_buf_size_]; probs_[iChunk + QV_RESET_CURRENT_PROB * prob_buf_size_] = p0; @@ -3103,7 +3098,6 @@ void QubitVectorThrust::apply_batched_kraus( std::vector &rng) { const size_t N = qubits.size(); uint_t i, count; - double ret; count = chunk_.container()->num_chunks(); @@ -3186,10 +3180,10 @@ template class bfunc_kernel : public Chunk::GateFuncBase { protected: uint_t bfunc_num_regs_; - Operations::RegComparison bfunc_; + Operations::BinaryOp bfunc_; public: - bfunc_kernel(uint_t n, Operations::RegComparison bfunc) { + bfunc_kernel(uint_t n, Operations::BinaryOp bfunc) { bfunc_num_regs_ = n; // number of registers to be updated bfunc_ = bfunc; } @@ -3215,26 +3209,26 @@ class bfunc_kernel : public Chunk::GateFuncBase { comp = (this->cregs_[iChunk * n64 + n64 - j - 1] & mask[n64 - j - 1]) - target[n64 - j - 1]; if (comp < 0) { - if (bfunc_ == Operations::RegComparison::Less || - bfunc_ == Operations::RegComparison::LessEqual) { + if (bfunc_ == Operations::BinaryOp::Less || + bfunc_ == Operations::BinaryOp::LessEqual) { break; - } else if (bfunc_ == Operations::RegComparison::Equal || - bfunc_ == Operations::RegComparison::Greater || - bfunc_ == Operations::RegComparison::GreaterEqual) { + } else if (bfunc_ == Operations::BinaryOp::Equal || + bfunc_ == Operations::BinaryOp::Greater || + bfunc_ == Operations::BinaryOp::GreaterEqual) { ret = false; break; } } else if (comp > 0) { - if (bfunc_ == Operations::RegComparison::Greater || - bfunc_ == Operations::RegComparison::GreaterEqual) { + if (bfunc_ == Operations::BinaryOp::Greater || + bfunc_ == Operations::BinaryOp::GreaterEqual) { break; - } else if (bfunc_ == Operations::RegComparison::Equal || - bfunc_ == Operations::RegComparison::Less || - bfunc_ == Operations::RegComparison::LessEqual) { + } else if (bfunc_ == Operations::BinaryOp::Equal || + bfunc_ == Operations::BinaryOp::Less || + bfunc_ == Operations::BinaryOp::LessEqual) { ret = false; break; } - } else if (bfunc_ == Operations::RegComparison::NotEqual && + } else if (bfunc_ == Operations::BinaryOp::NotEqual && mask[n64 - j - 1] != 0) { ret = false; break; @@ -3266,7 +3260,7 @@ void QubitVectorThrust::apply_bfunc(const Operations::Op &op) { return; // first chunk execute all in batch reg_t params; - int_t i, n64, n, iparam; + uint_t i, n64, n, iparam; // registers to be updated for (i = 0; i < op.registers.size(); i++) @@ -3299,7 +3293,7 @@ void QubitVectorThrust::apply_bfunc(const Operations::Op &op) { chunk_.StoreUintParams(params); - apply_function(bfunc_kernel(op.registers.size(), op.bfunc)); + apply_function(bfunc_kernel(op.registers.size(), op.binary_op)); chunk_.container()->request_creg_update(); } @@ -3377,7 +3371,7 @@ void QubitVectorThrust::apply_roerror(const Operations::Op &op, reg_t params; std::vector probs; - int_t i, j, offset; + uint_t i, offset; for (i = 0; i < op.memory.size(); i++) params.push_back(op.memory[i]); diff --git a/src/simulators/statevector/qv_avx2.cpp b/src/simulators/statevector/qv_avx2.cpp index 4d92ff8283..4053c34f97 100644 --- a/src/simulators/statevector/qv_avx2.cpp +++ b/src/simulators/statevector/qv_avx2.cpp @@ -43,7 +43,7 @@ namespace { /** Remember we cannot use STL (or memcpy) **/ template void copy(T dest, const U orig, size_t size) { - for (auto i = 0; i < size; ++i) + for (size_t i = 0; i < size; ++i) dest[i] = orig[i]; } @@ -1114,7 +1114,8 @@ Avx apply_diagonal_matrix_avx( #endif #if !defined(_WIN64) && !defined(_WIN32) void *data = nullptr; - posix_memalign(&data, 64, sizeof(std::complex) * 2); + if (posix_memalign(&data, 64, sizeof(std::complex) * 2) != 0) + throw std::runtime_error("Cannot allocate memory by posix_memalign"); auto double_tmp = reinterpret_cast *>(data); #else auto double_tmp = reinterpret_cast *>( @@ -1122,7 +1123,7 @@ Avx apply_diagonal_matrix_avx( #endif size_t q0_mask_ = 0; - for (int i = 0; i < qregs_size; ++i) { + for (size_t i = 0; i < qregs_size; ++i) { if (qregs[i] == 0) { q0_mask_ = 1UL << i; break; @@ -1135,9 +1136,9 @@ Avx apply_diagonal_matrix_avx( #pragma omp for for (int64_t k = 0; k < END; k += 1) { - const auto base = k << (batch + 1); - const auto until = base + (1UL << (batch + 1)); - for (auto i = base; i < until; i += 2) { + const int64_t base = k << (batch + 1); + const int64_t until = base + (1UL << (batch + 1)); + for (int64_t i = base; i < until; i += 2) { auto tgt_qv_data = _mm256_load(reinterpret_cast(&(qv_data[i]))); auto input_data = _load_diagonal_input(input_vec, double_tmp, i, qregs, @@ -1171,7 +1172,8 @@ Avx apply_diagonal_matrix_avx(float *qv_data_, const uint64_t data_size, { #if !defined(_WIN64) && !defined(_WIN32) void *data = nullptr; - posix_memalign(&data, 64, sizeof(std::complex) * 4); + if (posix_memalign(&data, 64, sizeof(std::complex) * 4) != 0) + throw std::runtime_error("Cannot allocate memory by posix_memalign"); auto float_tmp = reinterpret_cast *>(data); #else auto float_tmp = reinterpret_cast *>( @@ -1199,9 +1201,9 @@ Avx apply_diagonal_matrix_avx(float *qv_data_, const uint64_t data_size, #pragma omp for for (int64_t k = 0; k < END; k += 1) { - const auto base = k << (batch + 2); - const auto until = base + (1UL << (batch + 2)); - for (auto i = base; i < until; i += 4) { + const int64_t base = k << (batch + 2); + const int64_t until = base + (1UL << (batch + 2)); + for (int64_t i = base; i < until; i += 4) { m256_t tgt_qv_data = _mm256_load(reinterpret_cast(&(qv_data[i]))); auto input_data = _load_diagonal_input(input_vec, float_tmp, i, qregs, diff --git a/src/simulators/statevector/statevector_executor.hpp b/src/simulators/statevector/statevector_executor.hpp index 6cd6877211..5301035660 100644 --- a/src/simulators/statevector/statevector_executor.hpp +++ b/src/simulators/statevector/statevector_executor.hpp @@ -41,6 +41,7 @@ class Executor : public CircuitExecutor::ParallelStateExecutor, using Base = CircuitExecutor::MultiStateExecutor; using BasePar = CircuitExecutor::ParallelStateExecutor; using BaseBatch = CircuitExecutor::BatchShotsExecutor; + using Base::sample_measure; protected: public: @@ -434,7 +435,7 @@ bool Executor::apply_branching_op(CircuitExecutor::Branch &root, template void Executor::initialize_qreg(uint_t num_qubits) { - int_t i; + uint_t i; for (i = 0; i < Base::states_.size(); i++) { Base::states_[i].qreg().set_num_qubits(BasePar::chunk_bits_); @@ -442,8 +443,8 @@ void Executor::initialize_qreg(uint_t num_qubits) { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { if (Base::global_state_index_ + iChunk == 0 || this->num_qubits_ == this->chunk_bits_) { @@ -482,7 +483,7 @@ auto Executor::move_to_vector(void) { state.resize(Base::num_local_states_ << BasePar::chunk_bits_); #pragma omp parallel for if (BasePar::chunk_omp_parallel_) private(iChunk) - for (iChunk = 1; iChunk < Base::states_.size(); iChunk++) { + for (iChunk = 1; iChunk < (int_t)Base::states_.size(); iChunk++) { auto tmp = Base::states_[iChunk].qreg().move_to_vector(); uint_t j, offset = iChunk << BasePar::chunk_bits_; for (j = 0; j < tmp.size(); j++) { @@ -511,7 +512,7 @@ auto Executor::copy_to_vector(void) { state.resize(Base::num_local_states_ << BasePar::chunk_bits_); #pragma omp parallel for if (BasePar::chunk_omp_parallel_) private(iChunk) - for (iChunk = 1; iChunk < Base::states_.size(); iChunk++) { + for (iChunk = 1; iChunk < (int_t)Base::states_.size(); iChunk++) { auto tmp = Base::states_[iChunk].qreg().copy_to_vector(); uint_t j, offset = iChunk << BasePar::chunk_bits_; for (j = 0; j < tmp.size(); j++) { @@ -553,12 +554,12 @@ double Executor::expval_pauli(const reg_t &qubits, reg_t qubits_out_chunk; std::string pauli_in_chunk; std::string pauli_out_chunk; - int_t i, n; + uint_t n; double expval(0.); // get inner/outer chunk pauli string n = pauli.size(); - for (i = 0; i < n; i++) { + for (uint_t i = 0; i < n; i++) { if (qubits[i] < BasePar::chunk_bits_) { qubits_in_chunk.push_back(qubits[i]); pauli_in_chunk.push_back(pauli[n - i - 1]); @@ -583,18 +584,18 @@ double Executor::expval_pauli(const reg_t &qubits, if (x_mask != 0) { // pairing state is out of chunk bool on_same_process = true; #ifdef AER_MPI - int proc_bits = 0; + uint_t proc_bits = 0; uint_t procs = Base::distributed_procs_; while (procs > 1) { if ((procs & 1) != 0) { - proc_bits = -1; + proc_bits = 0; break; } proc_bits++; procs >>= 1; } - if (x_mask & (~((1ull << (Base::num_qubits_ - proc_bits)) - 1)) != - 0) { // data exchange between processes is required + if ((x_mask & (~((1ull << (Base::num_qubits_ - proc_bits)) - 1))) != + 0) { // data exchange between processes is required on_same_process = false; } #endif @@ -609,8 +610,8 @@ double Executor::expval_pauli(const reg_t &qubits, auto apply_expval_pauli_chunk = [this, x_mask, z_mask, x_max, mask_u, mask_l, qubits_in_chunk, pauli_in_chunk, phase](int_t iGroup) { - double expval = 0.0; - for (int_t iChunk = Base::top_state_of_group_[iGroup]; + double expval_t = 0.0; + for (uint_t iChunk = Base::top_state_of_group_[iGroup]; iChunk < Base::top_state_of_group_[iGroup + 1]; iChunk++) { uint_t pair_chunk = iChunk ^ x_mask; if (iChunk < pair_chunk) { @@ -618,20 +619,20 @@ double Executor::expval_pauli(const reg_t &qubits, z_count = AER::Utils::popcount(iChunk & z_mask); z_count_pair = AER::Utils::popcount(pair_chunk & z_mask); - expval += Base::states_[iChunk - Base::global_state_index_] - .qreg() - .expval_pauli(qubits_in_chunk, pauli_in_chunk, - Base::states_[pair_chunk].qreg(), - z_count, z_count_pair, phase); + expval_t += Base::states_[iChunk - Base::global_state_index_] + .qreg() + .expval_pauli(qubits_in_chunk, pauli_in_chunk, + Base::states_[pair_chunk].qreg(), + z_count, z_count_pair, phase); } } - return expval; + return expval_t; }; expval += Utils::apply_omp_parallel_for_reduction( (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1), 0, Base::num_global_states_ / 2, apply_expval_pauli_chunk); } else { - for (int_t i = 0; i < Base::num_global_states_ / 2; i++) { + for (uint_t i = 0; i < Base::num_global_states_ / 2; i++) { uint_t iChunk = ((i << 1) & mask_u) | (i & mask_l); uint_t pair_chunk = iChunk ^ x_mask; uint_t iProc = BasePar::get_process_by_chunk(pair_chunk); @@ -675,9 +676,9 @@ double Executor::expval_pauli(const reg_t &qubits, z_mask >>= BasePar::chunk_bits_; if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for reduction(+ : expval) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { double e_tmp = 0.0; - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { double sign = 1.0; if (z_mask && (AER::Utils::popcount( @@ -690,7 +691,7 @@ double Executor::expval_pauli(const reg_t &qubits, expval += e_tmp; } } else { - for (i = 0; i < Base::states_.size(); i++) { + for (uint_t i = 0; i < Base::states_.size(); i++) { double sign = 1.0; if (z_mask && (AER::Utils::popcount((i + Base::global_state_index_) & z_mask) & @@ -704,15 +705,15 @@ double Executor::expval_pauli(const reg_t &qubits, } else { // all bits are inside chunk if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for reduction(+ : expval) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { double e_tmp = 0.0; - for (int_t iChunk = Base::top_state_of_group_[ig]; + for (uint_t iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) e_tmp += Base::states_[iChunk].qreg().expval_pauli(qubits, pauli); expval += e_tmp; } } else { - for (i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) expval += Base::states_[i].qreg().expval_pauli(qubits, pauli); } } @@ -777,10 +778,10 @@ void Executor::apply_save_density_matrix(const Operations::Op &op, double sum = 0.0; if (BasePar::chunk_omp_parallel_) { #pragma omp parallel for reduction(+ : sum) - for (int_t i = 0; i < Base::states_.size(); i++) + for (int_t i = 0; i < (int_t)Base::states_.size(); i++) sum += Base::states_[i].qreg().norm(); } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) sum += Base::states_[i].qreg().norm(); } #ifdef AER_MPI @@ -906,7 +907,7 @@ template rvector_t Executor::measure_probs(const reg_t &qubits) const { uint_t dim = 1ull << qubits.size(); rvector_t sum(dim, 0.0); - int_t i, j, k; + uint_t i, j, k; reg_t qubits_in_chunk; reg_t qubits_out_chunk; @@ -916,8 +917,8 @@ rvector_t Executor::measure_probs(const reg_t &qubits) const { if (qubits_in_chunk.size() > 0) { if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(i, j, k) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) { auto chunkSum = Base::states_[i].qreg().probabilities(qubits_in_chunk); @@ -983,8 +984,8 @@ rvector_t Executor::measure_probs(const reg_t &qubits) const { } else { // there is no bit in chunk if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(i, j, k) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) { auto nr = std::real(Base::states_[i].qreg().norm()); int idx = 0; @@ -1002,7 +1003,7 @@ rvector_t Executor::measure_probs(const reg_t &qubits) const { } else { for (i = 0; i < Base::states_.size(); i++) { auto nr = std::real(Base::states_[i].qreg().norm()); - int idx = 0; + uint_t idx = 0; for (k = 0; k < qubits_out_chunk.size(); k++) { if ((((i + Base::global_state_index_) << (BasePar::chunk_bits_)) >> qubits_out_chunk[k]) & @@ -1058,14 +1059,14 @@ void Executor::measure_reset_update(const std::vector &qubits, if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].apply_diagonal_matrix(qubits, mdiag); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].apply_diagonal_matrix(qubits, mdiag); } @@ -1085,14 +1086,14 @@ void Executor::measure_reset_update(const std::vector &qubits, if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].apply_diagonal_matrix(qubits, mdiag); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].apply_diagonal_matrix(qubits, mdiag); } @@ -1120,20 +1121,20 @@ void Executor::measure_reset_update(const std::vector &qubits, // apply permutation to swap state if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, perm); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, perm); } } } else { - for (int_t i = 0; i < qubits.size(); i++) { + for (int_t i = 0; i < (int_t)qubits.size(); i++) { if (((final_state >> i) & 1) != ((meas_state >> i) & 1)) { BasePar::apply_chunk_x(qubits[i]); } @@ -1147,7 +1148,7 @@ template std::vector Executor::sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) const { - int_t i, j; + uint_t i, j; // Generate flat register for storing std::vector rnds; rnds.reserve(shots); @@ -1162,8 +1163,8 @@ std::vector Executor::sample_measure(const reg_t &qubits, // calculate per chunk sum if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) { bool batched = Base::states_[ic].qreg().enable_batch( true); // return sum of all chunks in group @@ -1172,8 +1173,8 @@ std::vector Executor::sample_measure(const reg_t &qubits, } } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) { bool batched = Base::states_[ic].qreg().enable_batch( true); // return sum of all chunks in group @@ -1259,10 +1260,23 @@ std::vector Executor::sample_measure(const reg_t &qubits, template void Executor::apply_initialize(const reg_t &qubits, - const cvector_t ¶ms, + const cvector_t ¶ms_in, RngEngine &rng) { auto sorted_qubits = qubits; std::sort(sorted_qubits.begin(), sorted_qubits.end()); + // apply global phase here + cvector_t tmp; + if (Base::states_[0].has_global_phase()) { + tmp.resize(params_in.size()); + std::complex global_phase = Base::states_[0].global_phase(); + auto apply_global_phase = [&tmp, ¶ms_in, global_phase](int_t i) { + tmp[i] = params_in[i] * global_phase; + }; + Utils::apply_omp_parallel_for( + (qubits.size() > (uint_t)Base::omp_qubit_threshold_), 0, + params_in.size(), apply_global_phase, Base::parallel_state_update_); + } + const cvector_t ¶ms = tmp.empty() ? params_in : tmp; if (qubits.size() == Base::num_qubits_) { // If qubits is all ordered qubits in the statevector // we can just initialize the whole state directly @@ -1283,13 +1297,13 @@ void Executor::apply_initialize(const reg_t &qubits, if (qubits_out_chunk.size() == 0) { // no qubits outside of chunk if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().initialize_component(qubits, params); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().initialize_component(qubits, params); } } else { @@ -1298,16 +1312,16 @@ void Executor::apply_initialize(const reg_t &qubits, // scatter inside chunks const size_t dim = 1ULL << qubits_in_chunk.size(); cvector_t perm(dim * dim, 0.); - for (int_t i = 0; i < dim; i++) { + for (uint_t i = 0; i < dim; i++) { perm[i] = 1.0; } if (BasePar::chunk_omp_parallel_) { #pragma omp parallel for - for (int_t i = 0; i < Base::states_.size(); i++) + for (int_t i = 0; i < (int_t)Base::states_.size(); i++) Base::states_[i].qreg().apply_matrix(qubits_in_chunk, perm); } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_matrix(qubits_in_chunk, perm); } } @@ -1316,8 +1330,9 @@ void Executor::apply_initialize(const reg_t &qubits, auto sorted_qubits_out = qubits_out_chunk; std::sort(sorted_qubits_out.begin(), sorted_qubits_out.end()); - for (int_t i = 0; i < (1ull << (Base::num_qubits_ - BasePar::chunk_bits_ - - qubits_out_chunk.size())); + for (uint_t i = 0; + i < (1ull << (Base::num_qubits_ - BasePar::chunk_bits_ - + qubits_out_chunk.size())); i++) { uint_t baseChunk = 0; uint_t j, ii, t; @@ -1331,7 +1346,7 @@ void Executor::apply_initialize(const reg_t &qubits, baseChunk >>= BasePar::chunk_bits_; for (j = 1; j < (1ull << qubits_out_chunk.size()); j++) { - int_t ic = baseChunk; + uint_t ic = baseChunk; for (t = 0; t < qubits_out_chunk.size(); t++) { if ((j >> t) & 1) ic += (1ull << (qubits_out_chunk[t] - BasePar::chunk_bits_)); @@ -1372,13 +1387,13 @@ void Executor::apply_initialize(const reg_t &qubits, // initialize by params if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) Base::states_[i].qreg().apply_diagonal_matrix(qubits, params); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) Base::states_[i].qreg().apply_diagonal_matrix(qubits, params); } } @@ -1389,7 +1404,7 @@ void Executor::initialize_from_vector(const cvector_t ¶ms) { uint_t local_offset = Base::global_state_index_ << BasePar::chunk_bits_; #pragma omp parallel for if (BasePar::chunk_omp_parallel_) - for (int_t i = 0; i < Base::states_.size(); i++) { + for (int_t i = 0; i < (int_t)Base::states_.size(); i++) { // copy part of state for this chunk cvector_t tmp(1ull << BasePar::chunk_bits_); std::copy(params.begin() + local_offset + (i << BasePar::chunk_bits_), @@ -1430,13 +1445,13 @@ void Executor::apply_kraus(const reg_t &qubits, p = 0.0; if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for reduction(+ : p) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t i = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t i = Base::top_state_of_group_[ig]; i < Base::top_state_of_group_[ig + 1]; i++) p += Base::states_[i].qreg().norm(qubits, vmat); } } else { - for (int_t i = 0; i < Base::states_.size(); i++) + for (uint_t i = 0; i < Base::states_.size(); i++) p += Base::states_[i].qreg().norm(qubits, vmat); } @@ -1452,14 +1467,14 @@ void Executor::apply_kraus(const reg_t &qubits, // apply Kraus projection operator if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, vmat); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, vmat); } @@ -1476,14 +1491,14 @@ void Executor::apply_kraus(const reg_t &qubits, auto vmat = Utils::vectorize_matrix(renorm * kmats.back()); if (BasePar::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, vmat); } } else { - for (int_t ig = 0; ig < Base::num_groups_; ig++) { - for (int_t ic = Base::top_state_of_group_[ig]; + for (uint_t ig = 0; ig < Base::num_groups_; ig++) { + for (uint_t ic = Base::top_state_of_group_[ig]; ic < Base::top_state_of_group_[ig + 1]; ic++) Base::states_[ic].qreg().apply_matrix(qubits, vmat); } @@ -1500,7 +1515,7 @@ Executor::sample_measure_with_prob(CircuitExecutor::Branch &root, uint_t nshots = root.num_shots(); reg_t shot_branch(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shot_branch[i] = root.rng_shots()[i].rand_int(probs); } @@ -1534,11 +1549,11 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, root.branches()[i]->add_op_after_branch(op); if (final_state >= 0 && final_state != i) { - Operations::Op op; - op.type = OpType::gate; - op.name = "mcx"; - op.qubits = qubits; - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::gate; + op2.name = "mcx"; + op2.qubits = qubits; + root.branches()[i]->add_op_after_branch(op2); } } } @@ -1546,7 +1561,7 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, else { // Diagonal matrix for projecting and renormalizing to measurement outcome const size_t dim = 1ULL << qubits.size(); - for (int_t i = 0; i < dim; i++) { + for (uint_t i = 0; i < dim; i++) { cvector_t mdiag(dim, 0.); mdiag[i] = 1. / std::sqrt(meas_probs[i]); @@ -1556,20 +1571,20 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, op.params = mdiag; root.branches()[i]->add_op_after_branch(op); - if (final_state >= 0 && final_state != i) { + if (final_state >= 0 && final_state != (int_t)i) { // build vectorized permutation matrix cvector_t perm(dim * dim, 0.); perm[final_state * dim + i] = 1.; perm[i * dim + final_state] = 1.; - for (size_t j = 0; j < dim; j++) { - if (j != final_state && j != i) + for (uint_t j = 0; j < dim; j++) { + if ((int_t)j != final_state && j != i) perm[j * dim + j] = 1.; } - Operations::Op op; - op.type = OpType::matrix; - op.qubits = qubits; - op.mats.push_back(Utils::devectorize_matrix(perm)); - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::matrix; + op2.qubits = qubits; + op2.mats.push_back(Utils::devectorize_matrix(perm)); + root.branches()[i]->add_op_after_branch(op2); } } } @@ -1582,7 +1597,7 @@ void Executor::apply_measure(CircuitExecutor::Branch &root, rvector_t probs = sample_measure_with_prob(root, qubits); // save result to cregs - for (int_t i = 0; i < probs.size(); i++) { + for (uint_t i = 0; i < probs.size(); i++) { const reg_t outcome = Utils::int2reg(i, 2, qubits.size()); root.branches()[i]->creg().store_measure(outcome, cmemory, cregister); } @@ -1601,7 +1616,21 @@ void Executor::apply_reset(CircuitExecutor::Branch &root, template void Executor::apply_initialize(CircuitExecutor::Branch &root, const reg_t &qubits, - const cvector_t ¶ms) { + const cvector_t ¶ms_in) { + // apply global phase here + cvector_t tmp; + if (Base::states_[root.state_index()].has_global_phase()) { + tmp.resize(params_in.size()); + std::complex global_phase = + Base::states_[root.state_index()].global_phase(); + auto apply_global_phase = [&tmp, params_in, global_phase](int_t i) { + tmp[i] = params_in[i] * global_phase; + }; + Utils::apply_omp_parallel_for( + (qubits.size() > (uint_t)Base::omp_qubit_threshold_), 0, + params_in.size(), apply_global_phase, Base::parallel_state_update_); + } + const cvector_t ¶ms = tmp.empty() ? params_in : tmp; if (qubits.size() == Base::num_qubits_) { auto sorted_qubits = qubits; std::sort(sorted_qubits.begin(), sorted_qubits.end()); @@ -1621,7 +1650,7 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, op.name = "initialize"; op.qubits = qubits; op.params = params; - for (int_t i = 0; i < root.num_branches(); i++) { + for (uint_t i = 0; i < root.num_branches(); i++) { root.branches()[i]->add_op_after_branch(op); } return; // initialization will be done in next call because of shot @@ -1645,10 +1674,8 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, // So we only compute probabilities for the first N-1 kraus operators // and infer the probability of the last one from 1 - sum of the previous - double r; double accum = 0.; double p; - bool complete = false; reg_t shot_branch; uint_t nshots; @@ -1658,7 +1685,7 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, nshots = root.num_shots(); shot_branch.resize(nshots); rshots.resize(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shot_branch[i] = kmats.size() - 1; rshots[i] = root.rng_shots()[i].rand(0., 1.); } @@ -1674,7 +1701,7 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, // check if we need to apply this operator pmats[j] = p; - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { if (shot_branch[i] >= kmats.size() - 1) { if (accum > rshots[i]) { shot_branch[i] = j; @@ -1683,23 +1710,21 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, } } if (nshots_multiplied >= nshots) { - complete = true; break; } } - // check if we haven't applied a kraus operator yet pmats[pmats.size() - 1] = 1. - accum; root.creg() = Base::states_[root.state_index()].creg(); root.branch_shots(shot_branch, kmats.size()); - for (int_t i = 0; i < kmats.size(); i++) { + for (uint_t i = 0; i < kmats.size(); i++) { Operations::Op op; op.type = OpType::matrix; op.qubits = qubits; op.mats.push_back(kmats[i]); p = 1 / std::sqrt(pmats[i]); - for (int_t j = 0; j < op.mats[0].size(); j++) + for (uint_t j = 0; j < op.mats[0].size(); j++) op.mats[0][j] *= p; root.branches()[i]->add_op_after_branch(op); } @@ -1721,7 +1746,7 @@ void Executor::apply_save_density_matrix(CircuitExecutor::Branch &root, } std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -1744,7 +1769,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, std::vector copied(Base::num_bind_params_, false); if (op.type == Operations::OpType::save_probs_ket) { // Convert to ket dict - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -1756,7 +1781,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, } } } else { - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -1783,7 +1808,7 @@ void Executor::apply_save_statevector(CircuitExecutor::Branch &root, if (last_op) { const auto v = Base::states_[root.state_index()].move_to_vector(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot(Base::states_[root.state_index()].creg(), key, v, @@ -1791,7 +1816,7 @@ void Executor::apply_save_statevector(CircuitExecutor::Branch &root, } } else { const auto v = Base::states_[root.state_index()].copy_to_vector(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot(Base::states_[root.state_index()].creg(), key, v, @@ -1814,7 +1839,7 @@ void Executor::apply_save_statevector_dict( for (auto const &it : state_ket) { result_state_ket[it.first] = it.second; } - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot( @@ -1839,7 +1864,7 @@ void Executor::apply_save_amplitudes(CircuitExecutor::Branch &root, amps[i] = Base::states_[root.state_index()].qreg().get_state(op.int_params[i]); } - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot( @@ -1853,7 +1878,7 @@ void Executor::apply_save_amplitudes(CircuitExecutor::Branch &root, op.int_params[i]); } std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -1871,7 +1896,7 @@ std::vector Executor::sample_measure(state_t &state, const reg_t &qubits, uint_t shots, std::vector &rng) const { - int_t i, j; + uint_t i; std::vector rnds; rnds.reserve(shots); diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 0922705ade..8408290b3d 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -173,7 +173,7 @@ class State : public QuantumState::State { // Apply instructions //----------------------------------------------------------------------- - // Applies a sypported Gate operation to the state class. + // Applies a supported Gate operation to the state class. // If the input is not in allowed_gates an exeption will be raised. void apply_gate(const Operations::Op &op); @@ -402,7 +402,6 @@ const stringmap_t State::gateset_( template void State::initialize_qreg(uint_t num_qubits) { - int_t i; initialize_omp(); BaseState::qreg_.set_num_qubits(num_qubits); @@ -426,8 +425,6 @@ void State::initialize_statevector(uint_t num_qubits, template void State::initialize_omp() { - uint_t i; - BaseState::qreg_.set_omp_threshold(omp_qubit_threshold_); if (BaseState::threads_ > 0) // set allowed OMP threads in qubitvector BaseState::qreg_.set_omp_threads(BaseState::threads_); @@ -701,7 +698,7 @@ cmatrix_t State::vec2density(const reg_t &qubits, const T &vec) { cmatrix_t densmat(DIM, DIM); if ((N == BaseState::qreg_.num_qubits()) && (qubits == qubits_sorted)) { const int_t mask = QV::MASKS[N]; -#pragma omp parallel for if (2 * N > omp_qubit_threshold_ && \ +#pragma omp parallel for if (2 * N > (size_t)omp_qubit_threshold_ && \ BaseState::threads_ > 1) \ num_threads(BaseState::threads_) for (int_t rowcol = 0; rowcol < int_t(DIM * DIM); ++rowcol) { @@ -750,7 +747,7 @@ void State::apply_gate(const Operations::Op &op) { } if (qubits_out.size() > 0) { uint_t mask = 0; - for (int i = 0; i < qubits_out.size(); i++) { + for (uint_t i = 0; i < qubits_out.size(); i++) { mask |= (1ull << (qubits_out[i] - BaseState::qreg_.num_qubits())); } if ((BaseState::qreg_.chunk_index() & mask) == mask) { @@ -1026,7 +1023,7 @@ template std::vector State::sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) { - int_t i, j; + uint_t i; // Generate flat register for storing std::vector rnds; rnds.reserve(shots); @@ -1055,10 +1052,22 @@ std::vector State::sample_measure(const reg_t &qubits, template void State::apply_initialize(const reg_t &qubits, - const cvector_t ¶ms, + const cvector_t ¶ms_in, RngEngine &rng) { auto sorted_qubits = qubits; std::sort(sorted_qubits.begin(), sorted_qubits.end()); + // apply global phase here + cvector_t tmp; + if (BaseState::has_global_phase_) { + tmp.resize(params_in.size()); + auto apply_global_phase = [&tmp, ¶ms_in, this](int_t i) { + tmp[i] = params_in[i] * BaseState::global_phase_; + }; + Utils::apply_omp_parallel_for( + (qubits.size() > (uint_t)omp_qubit_threshold_), 0, params_in.size(), + apply_global_phase, BaseState::threads_); + } + const cvector_t ¶ms = tmp.empty() ? params_in : tmp; if (qubits.size() == BaseState::qreg_.num_qubits()) { // If qubits is all ordered qubits in the statevector // we can just initialize the whole state directly diff --git a/src/simulators/statevector/transformer.hpp b/src/simulators/statevector/transformer.hpp index b9a5e36f10..93591849ea 100644 --- a/src/simulators/statevector/transformer.hpp +++ b/src/simulators/statevector/transformer.hpp @@ -244,9 +244,9 @@ void Transformer::apply_diagonal_matrix( auto func = [&](const areg_t<2> &inds, const cvector_t &_diag) -> void { for (int_t i = 0; i < 2; ++i) { - const int_t k = inds[i]; + const uint_t k = inds[i]; int_t iv = 0; - for (int_t j = 0; j < N; j++) + for (uint_t j = 0; j < N; j++) if ((k & (1ULL << qubits[j])) != 0) iv += (1ULL << j); if (_diag[iv] != (data_t)1.0) diff --git a/src/simulators/tensor_network/tensor.hpp b/src/simulators/tensor_network/tensor.hpp index daa233b517..635930cb44 100644 --- a/src/simulators/tensor_network/tensor.hpp +++ b/src/simulators/tensor_network/tensor.hpp @@ -177,7 +177,7 @@ void Tensor::set_conj(const reg_t &qubits, std::vector> &mat) { set(qubits, mat); - for (int i = 0; i < tensor_.size(); i++) + for (uint_t i = 0; i < tensor_.size(); i++) tensor_[i] = std::conj(tensor_[i]); sp_tensor_ = true; } diff --git a/src/simulators/tensor_network/tensor_net.hpp b/src/simulators/tensor_network/tensor_net.hpp index f4f9434382..32b7d52c0e 100644 --- a/src/simulators/tensor_network/tensor_net.hpp +++ b/src/simulators/tensor_network/tensor_net.hpp @@ -374,7 +374,7 @@ template TensorNet::TensorNet(const TensorNet &obj) {} template TensorNet::~TensorNet() { - int i; + uint_t i; for (i = 0; i < tensors_.size(); i++) { tensors_[i].reset(); } @@ -417,7 +417,7 @@ void TensorNet::buffer_statevector(void) const { std::vector extents_out(num_qubits_); // output tensor - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { modes_out[i] = modes_qubits_[i]; extents_out[i] = 2; } @@ -464,9 +464,9 @@ TensorNet::reduced_density_matrix(const reg_t &qubits) { uint_t nqubits = qubits.size(); // connect qubits not to be reduced - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { bool check = false; - for (int_t j = 0; j < qubits.size(); j++) { + for (uint_t j = 0; j < qubits.size(); j++) { if (i == qubits[j]) { check = true; break; @@ -491,7 +491,7 @@ TensorNet::reduced_density_matrix(const reg_t &qubits) { std::vector> trace; // output tensor - for (int_t i = 0; i < nqubits; i++) { + for (uint_t i = 0; i < nqubits; i++) { modes_out[i] = modes_qubits_[qubits[i]]; modes_out[i + nqubits] = modes_qubits_sp_[qubits[i]]; extents_out[i] = 2; @@ -505,9 +505,9 @@ TensorNet::reduced_density_matrix(const reg_t &qubits) { delete contractor; // recover connectted qubits - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { bool check = false; - for (int_t j = 0; j < qubits.size(); j++) { + for (uint_t j = 0; j < qubits.size(); j++) { if (i == qubits[j]) { check = true; break; @@ -538,7 +538,7 @@ void TensorNet::initialize_component(const reg_t &qubits, statevector_.clear(); // invalidate statevector buffer cvector_t state(state0.size()); - for (int_t i = 0; i < state0.size(); i++) + for (uint_t i = 0; i < state0.size(); i++) state[i] = (std::complex)state0[i]; tensors_.push_back(std::make_shared>()); @@ -547,7 +547,7 @@ void TensorNet::initialize_component(const reg_t &qubits, tensors_.push_back(std::make_shared>()); tensors_[last + 1]->set_conj(qubits, state); - for (int i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { modes_qubits_[qubits[i]] = mode_index_; tensors_[last]->modes()[i] = mode_index_++; qubits_[qubits[i]] = tensors_[last]; @@ -584,7 +584,7 @@ void TensorNet::add_tensor(const reg_t &qubits, tensors_.push_back(std::make_shared>()); uint_t last = tensors_.size() - 1; tensors_[last]->set(qubits, mat); - for (int i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { tensors_[last]->modes()[i] = modes_qubits_[qubits[i]]; modes_qubits_[qubits[i]] = mode_index_; tensors_[last]->modes()[qubits.size() + i] = mode_index_++; @@ -594,7 +594,7 @@ void TensorNet::add_tensor(const reg_t &qubits, tensors_.push_back(std::make_shared>()); last++; tensors_[last]->set_conj(qubits, mat); - for (int i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { tensors_[last]->modes()[i] = modes_qubits_sp_[qubits[i]]; modes_qubits_sp_[qubits[i]] = mode_index_; tensors_[last]->modes()[qubits.size() + i] = mode_index_++; @@ -614,13 +614,13 @@ void TensorNet::add_superop_tensor( uint_t last = tensors_.size() - 1; tensors_[last]->set(qubits, mat); - for (int i = 0; i < size; i++) { + for (uint_t i = 0; i < size; i++) { tensors_[last]->modes()[i] = modes_qubits_[qubits[i]]; modes_qubits_[qubits[i]] = mode_index_; tensors_[last]->modes()[size * 2 + i] = mode_index_++; qubits_[qubits[i]] = tensors_[last]; } - for (int i = 0; i < size; i++) { + for (uint_t i = 0; i < size; i++) { tensors_[last]->modes()[size + i] = modes_qubits_sp_[qubits[i]]; modes_qubits_sp_[qubits[i]] = mode_index_; tensors_[last]->modes()[size * 3 + i] = mode_index_++; @@ -636,7 +636,7 @@ void TensorNet::add_superop_tensor( template void TensorNet::initialize() { - int i; + uint_t i; if (statevector_.size() > 0) statevector_.clear(); // invalidate statevector buffer @@ -658,7 +658,7 @@ void TensorNet::initialize() { for (i = 0; i < num_qubits_; i++) { tensors_.push_back(std::make_shared>()); uint_t last = tensors_.size() - 1; - tensors_[last]->set({i}, init); + tensors_[last]->set({(int)i}, init); modes_qubits_[i] = mode_index_; tensors_[last]->modes()[0] = mode_index_++; @@ -667,7 +667,7 @@ void TensorNet::initialize() { for (i = 0; i < num_qubits_; i++) { // for super qubits tensors_.push_back(std::make_shared>()); uint_t last = tensors_.size() - 1; - tensors_[last]->set({i}, init); + tensors_[last]->set({(int)i}, init); modes_qubits_sp_[i] = mode_index_; tensors_[last]->modes()[0] = mode_index_++; @@ -700,19 +700,19 @@ void TensorNet::initialize(const TensorNet &obj) { template void TensorNet::initialize_from_matrix(const cmatrix_t &matrix0) { cvector_t matrix(matrix0.size()); - for (int_t i = 0; i < matrix0.size(); i++) + for (uint_t i = 0; i < matrix0.size(); i++) matrix[i] = (std::complex)matrix0[i]; tensors_.push_back(std::make_shared>()); uint_t last = tensors_.size() - 1; tensors_[last]->set(num_qubits_, matrix); - for (int i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { modes_qubits_[i] = mode_index_++; tensors_[last]->modes()[i] = modes_qubits_[i]; qubits_[i] = tensors_[last]; } - for (int i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { modes_qubits_sp_[i] = mode_index_++; tensors_[last]->modes()[i + num_qubits_] = modes_qubits_sp_[i]; qubits_sp_[i] = tensors_[last]; @@ -772,7 +772,6 @@ void TensorNet::apply_multiplexer(const reg_t &control_qubits, for (const auto &q : control_qubits) { qubits.push_back(q); } - size_t N = qubits.size(); cvector_t matMP(DIM * DIM, 0.0); uint_t b, i, j; @@ -794,11 +793,10 @@ template void TensorNet::apply_diagonal_matrix(const reg_t &qubits, const cvector_t &diag) { cvector_t mat(diag.size() * diag.size(), 0.0); - for (int_t i = 0; i < diag.size(); i++) { + for (uint_t i = 0; i < diag.size(); i++) { mat[i * (diag.size() + 1)] = diag[i]; } - Tensor *t = new Tensor; add_tensor(qubits, mat); } @@ -806,7 +804,7 @@ template void TensorNet::apply_diagonal_superop_matrix( const reg_t &qubits, const cvector_t &diag) { cvector_t mat(diag.size() * diag.size(), 0.0); - for (int_t i = 0; i < diag.size(); i++) { + for (uint_t i = 0; i < diag.size(); i++) { mat[i * (diag.size() + 1)] = diag[i]; } add_superop_tensor(qubits, mat); @@ -833,7 +831,7 @@ void TensorNet::apply_mcx(const reg_t &qubits) { reg_t qubits_t; qubits_t.push_back(qubits[qubits.size() - 1]); - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) qubits_t.push_back(qubits[i]); add_tensor(qubits_t, mat); @@ -850,7 +848,7 @@ void TensorNet::apply_mcy(const reg_t &qubits) { reg_t qubits_t; qubits_t.push_back(qubits[qubits.size() - 1]); - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) qubits_t.push_back(qubits[i]); add_tensor(qubits_t, mat); @@ -869,7 +867,7 @@ void TensorNet::apply_mcswap(const reg_t &qubits) { reg_t qubits_t; qubits_t.push_back(qubits[qubits.size() - 2]); qubits_t.push_back(qubits[qubits.size() - 1]); - for (int i = 0; i < qubits.size() - 2; i++) + for (uint_t i = 0; i < qubits.size() - 2; i++) qubits_t.push_back(qubits[i]); add_tensor(qubits_t, mat); @@ -886,7 +884,7 @@ void TensorNet::apply_mcphase(const reg_t &qubits, reg_t qubits_t; qubits_t.push_back(qubits[qubits.size() - 1]); - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) qubits_t.push_back(qubits[i]); add_tensor(qubits_t, mat); @@ -907,7 +905,7 @@ void TensorNet::apply_mcu(const reg_t &qubits, reg_t qubits_t; qubits_t.push_back(qubits[qubits.size() - 1]); - for (int i = 0; i < qubits.size() - 1; i++) + for (uint_t i = 0; i < qubits.size() - 1; i++) qubits_t.push_back(qubits[i]); add_tensor(qubits_t, matR); @@ -951,7 +949,7 @@ void TensorNet::apply_rotation(const reg_t &qubits, const Rotation r, template double TensorNet::norm() const { // connect qubits not used for trace - for (int_t i = 1; i < num_qubits_; i++) { + for (uint_t i = 1; i < num_qubits_; i++) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_sp_[i]) { qubits_sp_[i]->modes()[j] = modes_qubits_[i]; @@ -980,7 +978,7 @@ double TensorNet::norm() const { delete contractor; // restore connected qubits - for (int_t i = 1; i < num_qubits_; i++) { + for (uint_t i = 1; i < num_qubits_; i++) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_[i]) { qubits_sp_[i]->modes()[j] = modes_qubits_sp_[i]; @@ -1002,26 +1000,26 @@ double TensorNet::norm(const reg_t &qubits, // additional matrix std::vector> mat_t(mat.size()); - for (int_t i = 0; i < mat.size(); i++) + for (uint_t i = 0; i < mat.size(); i++) mat_t[i] = mat[i]; mat_tensors[0] = std::make_shared>(); mat_tensors[0]->set(qubits, mat_t); - for (int i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { mat_tensors[0]->modes()[i] = tmp_modes[qubits[i]]; tmp_modes[qubits[i]] = tmp_index; mat_tensors[0]->modes()[qubits.size() + i] = tmp_index++; } mat_tensors[1] = std::make_shared>(); mat_tensors[1]->set_conj(qubits, mat_t); - for (int i = 0; i < qubits.size(); i++) { + for (uint_t i = 0; i < qubits.size(); i++) { mat_tensors[1]->modes()[i] = tmp_modes_sp[qubits[i]]; tmp_modes_sp[qubits[i]] = tmp_index; mat_tensors[1]->modes()[qubits.size() + i] = tmp_index++; } // connect qubits not used for trace - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { if (i != qubits[0]) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_sp_[i]) { @@ -1054,7 +1052,7 @@ double TensorNet::norm(const reg_t &qubits, delete contractor; // restore connected qubits - for (int_t i = 1; i < num_qubits_; i++) { + for (uint_t i = 1; i < num_qubits_; i++) { if (i != qubits[0]) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == tmp_modes[i]) { @@ -1085,7 +1083,7 @@ double TensorNet::probability(const uint_t outcome) const { template std::vector TensorNet::probabilities() const { reg_t qubits(num_qubits_); - for (int_t i = 0; i < num_qubits_; i++) + for (uint_t i = 0; i < num_qubits_; i++) qubits[i] = i; return probabilities(qubits); } @@ -1099,9 +1097,9 @@ TensorNet::probabilities(const reg_t &qubits) const { std::vector extents_out(nqubits * 2); std::vector> trace; // connect qubits not to be measured - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { bool check = false; - for (int_t j = 0; j < qubits.size(); j++) { + for (uint_t j = 0; j < qubits.size(); j++) { if (i == qubits[j]) { check = true; break; @@ -1122,7 +1120,7 @@ TensorNet::probabilities(const reg_t &qubits) const { contractor->set_network(tensors_); // output tensor - for (int_t i = 0; i < nqubits; i++) { + for (uint_t i = 0; i < nqubits; i++) { modes_out[i] = modes_qubits_[qubits[i]]; modes_out[i + nqubits] = modes_qubits_sp_[qubits[i]]; extents_out[i] = 2; @@ -1147,9 +1145,9 @@ TensorNet::probabilities(const reg_t &qubits) const { delete contractor; // recover connected qubits - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { bool check = false; - for (int_t j = 0; j < qubits.size(); j++) { + for (uint_t j = 0; j < qubits.size(); j++) { if (i == qubits[j]) { check = true; break; @@ -1201,7 +1199,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, const reg_t &input_shot_index, const reg_t &input_measured_probs, const uint_t pos_measured) const { - const int_t SHOTS = rnds.size(); + const uint_t SHOTS = rnds.size(); /*--------------------------------------------------------------------------- | cccccccccccc | oooooooooooooo | ************** | xxxxxxxxxxxxxx | @@ -1233,7 +1231,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, // output tensor std::vector modes_out(nqubits * 2); std::vector extents_out(nqubits * 2); - for (int_t i = 0; i < nqubits; i++) { + for (uint_t i = 0; i < nqubits; i++) { modes_out[i] = modes_qubits_[pos_measured - nqubits + i]; modes_out[i + nqubits] = modes_qubits_sp_[pos_measured - nqubits + i]; extents_out[i] = 2; @@ -1245,7 +1243,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, // connect qubits not to be measured if (pos_measured - nqubits > 0) { - for (int_t i = 0; i < pos_measured - nqubits; i++) { + for (uint_t i = 0; i < pos_measured - nqubits; i++) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_sp_[i]) { qubits_sp_[i]->modes()[j] = modes_qubits_[i]; @@ -1266,7 +1264,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, shots[0] = rnds; shot_index[0] = input_shot_index; } else { - for (int_t i = 0; i < SHOTS; i++) { + for (uint_t i = 0; i < SHOTS; i++) { shots[input_sample_index[i]].push_back(rnds[i]); shot_index[input_sample_index[i]].push_back(input_shot_index[i]); } @@ -1276,7 +1274,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, std::vector>> measured_tensors; if (measured_qubits > 0) { measured_tensors.resize(measured_qubits * 2); - for (int_t i = 0; i < measured_qubits; i++) { + for (uint_t i = 0; i < measured_qubits; i++) { std::vector> prob(2, 0.0); prob[input_measured_probs[pos_measured + i]] = 1.0; measured_tensors[i * 2] = std::make_shared>(); @@ -1293,11 +1291,11 @@ void TensorNet::sample_measure_branch(std::vector &samples, // 1st loop, sampling each branch before traversing branches to reuse tensor // network - for (int_t ib = 0; ib < num_branches; ib++) { + for (uint_t ib = 0; ib < num_branches; ib++) { if (shots[ib].size() > 0) { if (nqubits_branch > 0) { // tensors for measuredirmed probabilities - for (int_t i = 0; i < nqubits_branch; i++) { + for (uint_t i = 0; i < nqubits_branch; i++) { std::vector> prob(2, 0.0); if (((ib >> i) & 1) == 0) prob[0] = 1.0; @@ -1317,7 +1315,7 @@ void TensorNet::sample_measure_branch(std::vector &samples, // recover connected qubits if (pos_measured - nqubits > 0) { - for (int_t i = 0; i < pos_measured - nqubits; i++) { + for (uint_t i = 0; i < pos_measured - nqubits; i++) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_[i]) { qubits_sp_[i]->modes()[j] = modes_qubits_sp_[i]; @@ -1326,16 +1324,16 @@ void TensorNet::sample_measure_branch(std::vector &samples, } } } - for (int_t i = 0; i < measured_tensors.size(); i++) + for (uint_t i = 0; i < measured_tensors.size(); i++) measured_tensors[i].reset(); delete contractor; // 2nd loop traverse branches if (pos_measured - nqubits > 0) { - for (int_t ib = 0; ib < num_branches; ib++) { + for (uint_t ib = 0; ib < num_branches; ib++) { if (shots[ib].size() > 0) { reg_t measured_probs = input_measured_probs; - for (int_t i = 0; i < nqubits_branch; i++) + for (uint_t i = 0; i < nqubits_branch; i++) measured_probs[pos_measured + i] = ((ib >> i) & 1); sample_measure_branch(samples, shots[ib], sample_index[ib], @@ -1345,15 +1343,15 @@ void TensorNet::sample_measure_branch(std::vector &samples, } } else { // save samples - for (int_t ib = 0; ib < num_branches; ib++) { + for (uint_t ib = 0; ib < num_branches; ib++) { if (shots[ib].size() > 0) { reg_t sample = input_measured_probs; - for (int_t i = 0; i < nqubits_branch; i++) + for (uint_t i = 0; i < nqubits_branch; i++) sample[pos_measured + i] = ((ib >> i) & 1); - for (int_t i = 0; i < shots[ib].size(); i++) { + for (uint_t i = 0; i < shots[ib].size(); i++) { uint_t shot_id = shot_index[ib][i]; samples[shot_id] = sample; - for (int_t j = 0; j < nqubits; j++) { + for (uint_t j = 0; j < nqubits; j++) { samples[shot_id][j] = ((sample_index[ib][i] >> j) & 1); } } @@ -1385,7 +1383,7 @@ double TensorNet::expval_pauli(const reg_t &qubits, mat_phase[3] = initial_phase; // add Pauli ops to qubits - for (int_t i = 0; i < size; i++) { + for (uint_t i = 0; i < size; i++) { cvector_t mat(4, 0.0); switch (pauli[size - 1 - i]) { @@ -1421,7 +1419,7 @@ double TensorNet::expval_pauli(const reg_t &qubits, } // connect qubits not used for trace - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { if (i != qubits[0]) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == modes_qubits_sp_[i]) { @@ -1454,7 +1452,7 @@ double TensorNet::expval_pauli(const reg_t &qubits, delete contractor; // restore connected qubits - for (int_t i = 0; i < num_qubits_; i++) { + for (uint_t i = 0; i < num_qubits_; i++) { if (i != qubits[0]) { for (int_t j = 0; j < qubits_sp_[i]->rank(); j++) { if (qubits_sp_[i]->modes()[j] == tmp_modes[i]) { @@ -1465,7 +1463,7 @@ double TensorNet::expval_pauli(const reg_t &qubits, } } - for (int_t i = 0; i < pauli_tensors.size(); i++) { + for (uint_t i = 0; i < pauli_tensors.size(); i++) { pauli_tensors[i].reset(); } diff --git a/src/simulators/tensor_network/tensor_net_contractor_cuTensorNet.hpp b/src/simulators/tensor_network/tensor_net_contractor_cuTensorNet.hpp index cc69b93e38..33abbf76cf 100644 --- a/src/simulators/tensor_network/tensor_net_contractor_cuTensorNet.hpp +++ b/src/simulators/tensor_network/tensor_net_contractor_cuTensorNet.hpp @@ -84,6 +84,7 @@ class RawTensorData { uint_t tensor_size_; uint_t additional_tensor_size_; uint_t out_size_; + uint_t work_size_limit_; uint_t work_size_; uint_t sampling_buffer_size_; @@ -484,6 +485,12 @@ uint_t RawTensorData::optimize_contraction(void) { cutensornetStatus_t err; cudaSetDevice(device_id_); + size_t freeMem, totalMem; + int nid = omp_get_num_threads(); + + HANDLE_CUDA_ERROR(cudaMemGetInfo(&freeMem, &totalMem)); + work_size_limit_ = (freeMem / nid) * 0.9; + /******************************* * Find "optimal" contraction order and slicing *******************************/ @@ -510,7 +517,7 @@ uint_t RawTensorData::optimize_contraction(void) { cutensornetGetErrorString(err)); err = cutensornetContractionOptimize(hTensorNet_, tn_desc_, optimizer_config_, - work_size_, optimizer_info_); + work_size_limit_, optimizer_info_); if (err != CUTENSORNET_STATUS_SUCCESS) assert_error("cutensornetContractionOptimize", cutensornetGetErrorString(err)); @@ -540,27 +547,26 @@ void RawTensorData::create_contraction_plan(bool use_autotune) { assert_error("cutensornetCreateWorkspaceDescriptor", cutensornetGetErrorString(err)); - uint64_t requiredWorkspaceSize = 0; - err = cutensornetWorkspaceComputeSizes(hTensorNet_, tn_desc_, optimizer_info_, - work_desc_); + int64_t requiredWorkspaceSize = 0; + err = cutensornetWorkspaceComputeContractionSizes( + hTensorNet_, tn_desc_, optimizer_info_, work_desc_); if (err != CUTENSORNET_STATUS_SUCCESS) assert_error("cutensornetWorkspaceComputeSizes", cutensornetGetErrorString(err)); - err = cutensornetWorkspaceGetSize( + err = cutensornetWorkspaceGetMemorySize( hTensorNet_, work_desc_, CUTENSORNET_WORKSIZE_PREF_MIN, - CUTENSORNET_MEMSPACE_DEVICE, &requiredWorkspaceSize); + CUTENSORNET_MEMSPACE_DEVICE, CUTENSORNET_WORKSPACE_SCRATCH, + &requiredWorkspaceSize); if (err != CUTENSORNET_STATUS_SUCCESS) assert_error("cutensornetWorkspaceGetSize", cutensornetGetErrorString(err)); - if (work_size_ < requiredWorkspaceSize) { - throw std::runtime_error("ERROR : TensorNet::contractor required memory " - "size for workspace is not enough"); - } + allocate_work(requiredWorkspaceSize); - err = cutensornetWorkspaceSet( + err = cutensornetWorkspaceSetMemory( hTensorNet_, work_desc_, CUTENSORNET_MEMSPACE_DEVICE, - thrust::raw_pointer_cast(dev_work_.data()), work_size_); + CUTENSORNET_WORKSPACE_SCRATCH, thrust::raw_pointer_cast(dev_work_.data()), + work_size_); if (err != CUTENSORNET_STATUS_SUCCESS) assert_error("cutensornetWorkspaceSet", cutensornetGetErrorString(err)); @@ -967,8 +973,6 @@ void TensorNetContractor_cuTensorNet::allocate_additional_tensors( template void TensorNetContractor_cuTensorNet::set_additional_tensors( const std::vector>> &tensors) { - uint_t size = 0; - remove_additional_tensors(); num_additional_tensors_ = tensors.size(); @@ -1021,10 +1025,6 @@ void TensorNetContractor_cuTensorNet::set_output( template void TensorNetContractor_cuTensorNet::setup_contraction( bool use_autotune) { - int nid = omp_get_num_threads(); - cutensornetStatus_t err; - size_t freeMem, totalMem; - uint_t work_size; // for MPI distribution #ifdef AER_MPI @@ -1032,14 +1032,6 @@ void TensorNetContractor_cuTensorNet::setup_contraction( MPI_Comm_rank(MPI_COMM_WORLD, &myrank_); #endif - // allocate work buffer on GPU - if (!tensor_data_[0].work_allocated()) { - cudaSetDevice(target_gpus_[0]); - HANDLE_CUDA_ERROR(cudaMemGetInfo(&freeMem, &totalMem)); - work_size = (freeMem / nid) * 0.9; - tensor_data_[0].allocate_work(work_size); - } - num_devices_used_ = 1; // setup first device @@ -1060,12 +1052,6 @@ void TensorNetContractor_cuTensorNet::setup_contraction( if (ns > 0) { // setup for the device - if (!tensor_data_[i].work_allocated()) { - cudaSetDevice(target_gpus_[i]); - HANDLE_CUDA_ERROR(cudaMemGetInfo(&freeMem, &totalMem)); - work_size = (freeMem / nid) * 0.9; - tensor_data_[i].allocate_work(work_size); - } tensor_data_[i].copy_tensors_from_device( tensor_data_[0]); // copy data from the first device tensor_data_[i].create_contraction_descriptor( diff --git a/src/simulators/tensor_network/tensor_net_executor.hpp b/src/simulators/tensor_network/tensor_net_executor.hpp index 102fb22c2f..53d24faf96 100644 --- a/src/simulators/tensor_network/tensor_net_executor.hpp +++ b/src/simulators/tensor_network/tensor_net_executor.hpp @@ -37,6 +37,7 @@ using ResultItr = std::vector::iterator; template class Executor : public CircuitExecutor::MultiStateExecutor { using Base = CircuitExecutor::MultiStateExecutor; + using Base::sample_measure; protected: public: @@ -148,7 +149,7 @@ Executor::sample_measure_with_prob(CircuitExecutor::Branch &root, uint_t nshots = root.num_shots(); reg_t shot_branch(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shot_branch[i] = root.rng_shots()[i].rand_int(probs); } @@ -182,11 +183,11 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, root.branches()[i]->add_op_after_branch(op); if (final_state >= 0 && final_state != i) { - Operations::Op op; - op.type = OpType::gate; - op.name = "mcx"; - op.qubits = qubits; - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::gate; + op2.name = "mcx"; + op2.qubits = qubits; + root.branches()[i]->add_op_after_branch(op2); } } } @@ -194,7 +195,7 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, else { // Diagonal matrix for projecting and renormalizing to measurement outcome const size_t dim = 1ULL << qubits.size(); - for (int_t i = 0; i < dim; i++) { + for (uint_t i = 0; i < dim; i++) { cvector_t mdiag(dim, 0.); mdiag[i] = 1. / std::sqrt(meas_probs[i]); @@ -204,20 +205,20 @@ void Executor::measure_reset_update(CircuitExecutor::Branch &root, op.params = mdiag; root.branches()[i]->add_op_after_branch(op); - if (final_state >= 0 && final_state != i) { + if (final_state >= 0 && final_state != (int_t)i) { // build vectorized permutation matrix cvector_t perm(dim * dim, 0.); perm[final_state * dim + i] = 1.; perm[i * dim + final_state] = 1.; for (size_t j = 0; j < dim; j++) { - if (j != final_state && j != i) + if (j != (size_t)final_state && j != i) perm[j * dim + j] = 1.; } - Operations::Op op; - op.type = OpType::matrix; - op.qubits = qubits; - op.mats.push_back(Utils::devectorize_matrix(perm)); - root.branches()[i]->add_op_after_branch(op); + Operations::Op op2; + op2.type = OpType::matrix; + op2.qubits = qubits; + op2.mats.push_back(Utils::devectorize_matrix(perm)); + root.branches()[i]->add_op_after_branch(op2); } } } @@ -230,7 +231,7 @@ void Executor::apply_measure(CircuitExecutor::Branch &root, rvector_t probs = sample_measure_with_prob(root, qubits); // save result to cregs - for (int_t i = 0; i < probs.size(); i++) { + for (uint_t i = 0; i < probs.size(); i++) { const reg_t outcome = Utils::int2reg(i, 2, qubits.size()); root.branches()[i]->creg().store_measure(outcome, cmemory, cregister); } @@ -249,7 +250,21 @@ void Executor::apply_reset(CircuitExecutor::Branch &root, template void Executor::apply_initialize(CircuitExecutor::Branch &root, const reg_t &qubits, - const cvector_t ¶ms) { + const cvector_t ¶ms_in) { + // apply global phase here + cvector_t tmp; + if (Base::states_[root.state_index()].has_global_phase()) { + tmp.resize(params_in.size()); + std::complex global_phase = + Base::states_[root.state_index()].global_phase(); + auto apply_global_phase = [&tmp, params_in, global_phase](int_t i) { + tmp[i] = params_in[i] * global_phase; + }; + Utils::apply_omp_parallel_for( + (qubits.size() > (uint_t)Base::omp_qubit_threshold_), 0, + params_in.size(), apply_global_phase, Base::parallel_state_update_); + } + const cvector_t ¶ms = tmp.empty() ? params_in : tmp; if (qubits.size() == Base::num_qubits_) { auto sorted_qubits = qubits; std::sort(sorted_qubits.begin(), sorted_qubits.end()); @@ -269,7 +284,7 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, op.name = "initialize"; op.qubits = qubits; op.params = params; - for (int_t i = 0; i < root.num_branches(); i++) { + for (uint_t i = 0; i < root.num_branches(); i++) { root.branches()[i]->add_op_after_branch(op); } return; // initialization will be done in next call because of shot @@ -293,10 +308,8 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, // So we only compute probabilities for the first N-1 kraus operators // and infer the probability of the last one from 1 - sum of the previous - double r; double accum = 0.; double p; - bool complete = false; reg_t shot_branch; uint_t nshots; @@ -306,7 +319,7 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, nshots = root.num_shots(); shot_branch.resize(nshots); rshots.resize(nshots); - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { shot_branch[i] = kmats.size() - 1; rshots[i] = root.rng_shots()[i].rand(0., 1.); } @@ -322,7 +335,7 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, // check if we need to apply this operator pmats[j] = p; - for (int_t i = 0; i < nshots; i++) { + for (uint_t i = 0; i < nshots; i++) { if (shot_branch[i] >= kmats.size() - 1) { if (accum > rshots[i]) { shot_branch[i] = j; @@ -331,7 +344,6 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, } } if (nshots_multiplied >= nshots) { - complete = true; break; } } @@ -341,13 +353,13 @@ void Executor::apply_kraus(CircuitExecutor::Branch &root, root.creg() = Base::states_[root.state_index()].creg(); root.branch_shots(shot_branch, kmats.size()); - for (int_t i = 0; i < kmats.size(); i++) { + for (uint_t i = 0; i < kmats.size(); i++) { Operations::Op op; op.type = OpType::matrix; op.qubits = qubits; op.mats.push_back(kmats[i]); p = 1 / std::sqrt(pmats[i]); - for (int_t j = 0; j < op.mats[0].size(); j++) + for (uint_t j = 0; j < op.mats[0].size(); j++) op.mats[0][j] *= p; root.branches()[i]->add_op_after_branch(op); } @@ -371,7 +383,7 @@ void Executor::apply_save_density_matrix(CircuitExecutor::Branch &root, } std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -394,7 +406,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, std::vector copied(Base::num_bind_params_, false); if (op.type == Operations::OpType::save_probs_ket) { // Convert to ket dict - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -406,7 +418,7 @@ void Executor::apply_save_probs(CircuitExecutor::Branch &root, } } } else { - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -433,7 +445,7 @@ void Executor::apply_save_statevector(CircuitExecutor::Branch &root, if (last_op) { const auto v = Base::states_[root.state_index()].move_to_vector(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot(Base::states_[root.state_index()].creg(), key, v, @@ -441,7 +453,7 @@ void Executor::apply_save_statevector(CircuitExecutor::Branch &root, } } else { const auto v = Base::states_[root.state_index()].copy_to_vector(); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot(Base::states_[root.state_index()].creg(), key, v, @@ -464,7 +476,7 @@ void Executor::apply_save_statevector_dict( for (auto const &it : state_ket) { result_state_ket[it.first] = it.second; } - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot( @@ -482,14 +494,14 @@ void Executor::apply_save_amplitudes(CircuitExecutor::Branch &root, throw std::invalid_argument( "Invalid save_amplitudes instructions (empty params)."); } - const int_t size = op.int_params.size(); + const uint_t size = op.int_params.size(); if (op.type == Operations::OpType::save_amps) { Vector amps(size, false); - for (int_t i = 0; i < size; ++i) { + for (uint_t i = 0; i < size; ++i) { amps[i] = Base::states_[root.state_index()].qreg().get_state(op.int_params[i]); } - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); (result + ip) ->save_data_pershot( @@ -498,12 +510,12 @@ void Executor::apply_save_amplitudes(CircuitExecutor::Branch &root, } } else { rvector_t amps_sq(size, 0); - for (int_t i = 0; i < size; ++i) { + for (uint_t i = 0; i < size; ++i) { amps_sq[i] = Base::states_[root.state_index()].qreg().probability( op.int_params[i]); } std::vector copied(Base::num_bind_params_, false); - for (int_t i = 0; i < root.num_shots(); i++) { + for (uint_t i = 0; i < root.num_shots(); i++) { uint_t ip = root.param_index(i); if (!copied[ip]) { (result + ip) @@ -525,23 +537,23 @@ Executor::sample_measure(state_t &state, const reg_t &qubits, std::vector rnds; rnds.reserve(shots); - for (i = 0; i < shots; ++i) + for (i = 0; i < (int_t)shots; ++i) rnds.push_back(rng[i].rand(0, 1)); std::vector samples = state.qreg().sample_measure(rnds); std::vector ret(shots); if (omp_get_num_threads() > 1) { - for (i = 0; i < shots; ++i) { + for (i = 0; i < (int_t)shots; ++i) { ret[i].resize(qubits.size()); - for (j = 0; j < qubits.size(); j++) + for (j = 0; j < (int_t)qubits.size(); j++) ret[i][j] = samples[i][qubits[j]]; } } else { #pragma omp parallel for private(j) - for (i = 0; i < shots; ++i) { + for (i = 0; i < (int_t)shots; ++i) { ret[i].resize(qubits.size()); - for (j = 0; j < qubits.size(); j++) + for (j = 0; j < (int_t)qubits.size(); j++) ret[i][j] = samples[i][qubits[j]]; } } diff --git a/src/simulators/tensor_network/tensor_net_state.hpp b/src/simulators/tensor_network/tensor_net_state.hpp index f302e8a470..ef0bbf3a10 100644 --- a/src/simulators/tensor_network/tensor_net_state.hpp +++ b/src/simulators/tensor_network/tensor_net_state.hpp @@ -899,27 +899,26 @@ template std::vector State::sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) { - int_t i, j; // Generate flat register for storing std::vector rnds(shots); - for (i = 0; i < shots; ++i) + for (uint_t i = 0; i < shots; ++i) rnds[i] = rng.rand(0, 1); std::vector samples = BaseState::qreg_.sample_measure(rnds); std::vector ret(shots); if (omp_get_num_threads() > 1) { - for (i = 0; i < shots; ++i) { + for (uint_t i = 0; i < shots; ++i) { ret[i].resize(qubits.size()); - for (j = 0; j < qubits.size(); j++) + for (uint_t j = 0; j < qubits.size(); j++) ret[i][j] = samples[i][qubits[j]]; } } else { -#pragma omp parallel for private(j) - for (i = 0; i < shots; ++i) { +#pragma omp parallel for + for (int_t i = 0; i < (int_t)shots; ++i) { ret[i].resize(qubits.size()); - for (j = 0; j < qubits.size(); j++) + for (uint_t j = 0; j < qubits.size(); j++) ret[i][j] = samples[i][qubits[j]]; } } @@ -928,10 +927,21 @@ std::vector State::sample_measure(const reg_t &qubits, template void State::apply_initialize(const reg_t &qubits, - const cvector_t ¶ms, + const cvector_t ¶ms_in, RngEngine &rng) { auto sorted_qubits = qubits; std::sort(sorted_qubits.begin(), sorted_qubits.end()); + // apply global phase here + cvector_t tmp; + if (BaseState::has_global_phase_) { + tmp.resize(params_in.size()); + auto apply_global_phase = [&tmp, params_in, this](int_t i) { + tmp[i] = params_in[i] * BaseState::global_phase_; + }; + Utils::apply_omp_parallel_for((qubits.size() > 14), 0, params_in.size(), + apply_global_phase, BaseState::threads_); + } + const cvector_t ¶ms = tmp.empty() ? params_in : tmp; if (qubits.size() == BaseState::qreg_.num_qubits()) { // If qubits is all ordered qubits in the statevector // we can just initialize the whole state directly @@ -952,7 +962,7 @@ void State::initialize_from_vector( BaseState::qreg_.initialize(); reg_t qubits(BaseState::qreg_.num_qubits()); - for (int_t i = 0; i < BaseState::qreg_.num_qubits(); i++) + for (uint_t i = 0; i < BaseState::qreg_.num_qubits(); i++) qubits[i] = i; BaseState::qreg_.initialize_component(qubits, params); } diff --git a/src/simulators/unitary/unitary_executor.hpp b/src/simulators/unitary/unitary_executor.hpp index 3066e0d619..3cc2414668 100644 --- a/src/simulators/unitary/unitary_executor.hpp +++ b/src/simulators/unitary/unitary_executor.hpp @@ -84,14 +84,14 @@ void Executor::set_config(const Config &config) { template void Executor::initialize_qreg(uint_t num_qubits) { - int_t iChunk; + uint_t iChunk; for (iChunk = 0; iChunk < Base::states_.size(); iChunk++) { Base::states_[iChunk].qreg().set_num_qubits(Base::chunk_bits_); } if (Base::chunk_omp_parallel_ && Base::num_groups_ > 1) { #pragma omp parallel for private(iChunk) - for (int_t ig = 0; ig < Base::num_groups_; ig++) { + for (int_t ig = 0; ig < (int_t)Base::num_groups_; ig++) { for (iChunk = Base::top_state_of_group_[ig]; iChunk < Base::top_state_of_group_[ig + 1]; iChunk++) { uint_t irow, icol; diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index 8f33e43ce1..8fbad7d4a1 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -369,7 +369,6 @@ void State::initialize_qreg(uint_t num_qubits, template void State::initialize_omp() { - uint_t i; BaseState::qreg_.set_omp_threshold(omp_qubit_threshold_); if (BaseState::threads_ > 0) BaseState::qreg_.set_omp_threads( @@ -414,7 +413,7 @@ void State::apply_gate(const Operations::Op &op) { } if (qubits_out.size() > 0) { uint_t mask = 0; - for (int i = 0; i < qubits_out.size(); i++) { + for (uint_t i = 0; i < qubits_out.size(); i++) { mask |= (1ull << (qubits_out[i] - BaseState::qreg_.num_qubits())); } if ((BaseState::qreg_.chunk_index() & mask) == mask) { diff --git a/src/simulators/unitary/unitarymatrix.hpp b/src/simulators/unitary/unitarymatrix.hpp index f406091662..7fd6170d57 100644 --- a/src/simulators/unitary/unitarymatrix.hpp +++ b/src/simulators/unitary/unitarymatrix.hpp @@ -237,7 +237,6 @@ void UnitaryMatrix::initialize() { // Zero the underlying vector BaseVector::zero(); // Set to be identity matrix - const int_t nrows = rows_; // end for k loop auto initialize_proc = [this](int_t i) { BaseVector::data_[i * (rows_ + 1)] = 1.0; }; @@ -261,7 +260,7 @@ void UnitaryMatrix::initialize_from_matrix( ")."); } auto initialize_proc = [this, &mat](int_t row) { - for (int_t col = 0; col < rows_; ++col) { + for (uint_t col = 0; col < rows_; ++col) { BaseVector::data_[row + rows_ * col] = mat(row, col); } }; diff --git a/src/simulators/unitary/unitarymatrix_thrust.hpp b/src/simulators/unitary/unitarymatrix_thrust.hpp index 8687f8e2c7..58a15f79c8 100755 --- a/src/simulators/unitary/unitarymatrix_thrust.hpp +++ b/src/simulators/unitary/unitarymatrix_thrust.hpp @@ -212,13 +212,11 @@ UnitaryMatrixThrust::copy_to_matrix() const { cvector_t qreg = BaseVector::vector(); - int_t i; - uint_t irow, icol; -#pragma omp parallel for private( \ - i, irow, icol) if (BaseVector::num_qubits_ > BaseVector::omp_threshold_ && \ - BaseVector::omp_threads_ > 1) \ +#pragma omp parallel for if (BaseVector::num_qubits_ > \ + BaseVector::omp_threshold_ && \ + BaseVector::omp_threads_ > 1) \ num_threads(BaseVector::omp_threads_) - for (i = 0; i < csize; i++) { + for (int_t i = 0; i < (int_t)csize; i++) { ret[i] = qreg[i]; } return ret; diff --git a/src/transpile/batch_converter.hpp b/src/transpile/batch_converter.hpp index 40e1b65537..85766780bb 100644 --- a/src/transpile/batch_converter.hpp +++ b/src/transpile/batch_converter.hpp @@ -100,7 +100,7 @@ void BatchConverter::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, const opset_t &allowed_opset, ExperimentResult &result) const { // convert operations for batch shots execution - for (int_t i = 0; i < circ.ops.size(); i++) { + for (uint_t i = 0; i < circ.ops.size(); i++) { if (circ.ops[i].has_bind_params) { if (circ.ops[i].type == Operations::OpType::gate) { gate_to_matrix(circ.ops[i], circ.num_bind_params); @@ -108,8 +108,8 @@ void BatchConverter::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, // convert matrix to cvector_t in params uint_t matrix_size = circ.ops[i].mats[0].size(); circ.ops[i].params.resize(matrix_size * circ.num_bind_params); - for (int_t j = 0; j < circ.num_bind_params; j++) { - for (int_t k = 0; k < matrix_size; k++) + for (uint_t j = 0; j < circ.num_bind_params; j++) { + for (uint_t k = 0; k < matrix_size; k++) circ.ops[i].params[j * matrix_size + k] = circ.ops[i].mats[j][k]; } circ.ops[i].mats.clear(); @@ -120,7 +120,7 @@ void BatchConverter::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, // convert global phase to diagonal matrix if (circ.global_phase_for_params.size() == circ.num_bind_params) { bool has_global_phase = false; - for (int_t j = 0; j < circ.num_bind_params; j++) { + for (uint_t j = 0; j < circ.num_bind_params; j++) { if (!Linalg::almost_equal(circ.global_phase_for_params[j], 0.0)) { has_global_phase = true; break; @@ -132,7 +132,7 @@ void BatchConverter::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, phase_op.type = Operations::OpType::diagonal_matrix; phase_op.has_bind_params = true; phase_op.params.resize(2 * circ.num_bind_params); - for (int_t j = 0; j < circ.num_bind_params; j++) { + for (uint_t j = 0; j < circ.num_bind_params; j++) { auto t = std::exp(complex_t(0.0, circ.global_phase_for_params[j])); phase_op.params[j * 2] = t; phase_op.params[j * 2 + 1] = t; @@ -173,64 +173,64 @@ void BatchConverter::gate_to_matrix(Operations::Op &op, auto store_matrix = [&matrix_array, matrix_size](int_t iparam, cvector_t mat) { - for (int_t j = 0; j < matrix_size; j++) + for (uint_t j = 0; j < matrix_size; j++) matrix_array[iparam * matrix_size + j] = mat[j]; }; switch (it->second) { case ParamGates::mcr: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::r(op.params[i * 2], op.params[i * 2 + 1])); break; case ParamGates::mcrx: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::rx(std::real(op.params[i]))); break; case ParamGates::mcry: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::ry(std::real(op.params[i]))); break; case ParamGates::mcrz: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::rz_diag(std::real(op.params[i]))); break; case ParamGates::rxx: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::rxx(std::real(op.params[i]))); break; case ParamGates::ryy: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::ryy(std::real(op.params[i]))); break; case ParamGates::rzz: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::rzz_diag(std::real(op.params[i]))); break; case ParamGates::rzx: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::rzx(std::real(op.params[i]))); break; case ParamGates::mcu3: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::u3(std::real(op.params[i * 3]), std::real(op.params[i * 3 + 1]), std::real(op.params[i * 3 + 2]))); break; case ParamGates::mcu: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::u4(std::real(op.params[i * 4]), std::real(op.params[i * 4 + 1]), std::real(op.params[i * 4 + 2]), std::real(op.params[i * 4 + 3]))); break; case ParamGates::mcu2: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::u2(std::real(op.params[i * 2]), std::real(op.params[i * 2 + 1]))); break; case ParamGates::mcp: - for (int_t i = 0; i < num_params; i++) + for (uint_t i = 0; i < num_params; i++) store_matrix(i, Linalg::VMatrix::phase_diag(std::real(op.params[i]))); break; default: diff --git a/src/transpile/cacheblocking.hpp b/src/transpile/cacheblocking.hpp index 35d72908c0..9989264347 100644 --- a/src/transpile/cacheblocking.hpp +++ b/src/transpile/cacheblocking.hpp @@ -68,16 +68,16 @@ class CacheBlocking : public CircuitOptimization { void set_num_processes(int np) { num_processes_ = np; } protected: - mutable int block_bits_; // qubits less than this will be blocked - mutable int qubits_; + mutable uint_t block_bits_; // qubits less than this will be blocked + mutable uint_t qubits_; mutable reg_t qubitMap_; mutable reg_t qubitSwapped_; mutable bool blocking_enabled_; mutable bool sample_measure_ = false; mutable bool restore_qubit_map_ = false; - int memory_blocking_bits_ = 0; + uint_t memory_blocking_bits_ = 0; bool density_matrix_ = false; - int num_processes_ = 1; + uint_t num_processes_ = 1; bool block_circuit(Circuit &circ, bool doSwap) const; @@ -150,7 +150,6 @@ void CacheBlocking::set_blocking(int bits, size_t min_memory, uint_t n_place, size_t complex_size, bool is_matrix) { int chunk_bits = bits; uint_t scale = is_matrix ? 2 : 1; - size_t size; // get largest possible chunk bits while ((complex_size << (scale * chunk_bits)) > min_memory) { @@ -215,7 +214,7 @@ void CacheBlocking::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, // loop over operations to find max number of parameters for cross-qubits // operations - int_t max_params = 1; + uint_t max_params = 1; for (uint_t i = 0; i < circ.ops.size(); i++) { if (is_blockable_operation(circ.ops[i]) && is_cross_qubits_op(circ.ops[i])) { @@ -302,7 +301,7 @@ void CacheBlocking::define_blocked_qubits(std::vector &ops, reg_t &blockedQubits, bool crossQubitOnly) const { uint_t i, j, iq; - int nq, nb; + uint_t nq; bool exist; for (i = 0; i < ops.size(); i++) { if (blockedQubits.size() >= block_bits_) @@ -384,7 +383,7 @@ bool CacheBlocking::can_reorder( } bool CacheBlocking::block_circuit(Circuit &circ, bool doSwap) const { - uint_t i, n; + uint_t n; std::vector out; std::vector queue; std::vector queue_next; @@ -523,11 +522,8 @@ uint_t CacheBlocking::add_ops(std::vector &ops, std::vector &queue, bool doSwap, bool first, bool crossQubitOnly) const { uint_t i, j, iq; - - int nqubitUsed = 0; reg_t blockedQubits; - int nq; - bool exist; + uint_t nq; uint_t pos_begin, num_gates_added; bool end_block_inserted; @@ -807,7 +803,7 @@ bool CacheBlocking::split_pauli(const Operations::Op &op, reg_t qubits_out_chunk; std::string pauli_in_chunk; std::string pauli_out_chunk; - int_t i, j, n; + uint_t i, j, n; bool inside; // get inner/outer chunk pauli string @@ -857,7 +853,7 @@ bool CacheBlocking::split_op(const Operations::Op &op, std::vector &queue) const { reg_t qubits_in_chunk; reg_t qubits_out_chunk; - int_t i, j, n; + uint_t i, j, n; bool inside; n = op.qubits.size(); diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index 23a48a6d5b..af8ec073ae 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -63,11 +63,11 @@ class FusionMethod { for (size_t i = 0; i < vec.size(); ++i) vec[i] = fusioned_op.mats[0](i, i); fusioned_op = Operations::make_diagonal( - fusioned_op.qubits, std::move(vec), std::string("fusion")); + fusioned_op.qubits, std::move(vec), -1, std::string("fusion")); } } else { // loop for runtime parameter binding - for (int_t p = 0; p < num_params_; p++) { + for (uint_t p = 0; p < num_params_; p++) { std::vector ops; ops.reserve(fusioned_ops.size()); for (auto &op : fusioned_ops) { @@ -83,7 +83,7 @@ class FusionMethod { vec.assign((1UL << new_op.qubits.size()), 0); for (size_t i = 0; i < vec.size(); ++i) vec[i] = new_op.mats[0](i, i); - new_op = Operations::make_diagonal(new_op.qubits, std::move(vec), + new_op = Operations::make_diagonal(new_op.qubits, std::move(vec), -1, std::string("fusion")); } @@ -449,18 +449,18 @@ bool NQubitFusion::aggregate_operations(oplist_t &ops, std::vector>> targets; bool fused = false; - for (uint_t op_idx = fusion_start; op_idx < fusion_end; ++op_idx) { + for (int op_idx = fusion_start; op_idx < fusion_end; ++op_idx) { // skip operations to be ignored if (!method.can_apply(ops[op_idx], max_fused_qubits) || ops[op_idx].type == optype_t::nop) continue; // 1. find a N-qubit operation - if (ops[op_idx].qubits.size() != N) + if (ops[op_idx].qubits.size() != N) { continue; + } - std::vector fusing_op_idxs = {op_idx}; - + std::vector fusing_op_idxs = {(uint_t)op_idx}; std::vector fusing_qubits; fusing_qubits.insert(fusing_qubits.end(), ops[op_idx].qubits.begin(), ops[op_idx].qubits.end()); @@ -895,14 +895,14 @@ void Fusion::optimize_circuit(Circuit &circ, Noise::NoiseModel &noise, if (parallelization_ > 1) { #pragma omp parallel for num_threads(parallelization_) - for (int_t i = 0; i < parallelization_; i++) { + for (int_t i = 0; i < (int_t)parallelization_; i++) { int_t start = unit * i; int_t end = std::min(start + unit, (int_t)circ.ops.size()); optimize_circuit(circ, noise, allowed_opset, start, end, fuser, method); } } else { - for (int_t i = 0; i < parallelization_; i++) { + for (uint_t i = 0; i < parallelization_; i++) { int_t start = unit * i; int_t end = std::min(start + unit, (int_t)circ.ops.size()); optimize_circuit(circ, noise, allowed_opset, start, end, fuser, diff --git a/test/asv.linux.conf.json b/test/asv.linux.conf.json index 279a5b1773..c5c72ec389 100644 --- a/test/asv.linux.conf.json +++ b/test/asv.linux.conf.json @@ -33,18 +33,18 @@ "install_command": [ "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit', True)\"", "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info', True)\"", - "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit", "pip install git+https://github.com/Qiskit/qiskit-aqua", "python -mpip install {wheel_file}" ], "uninstall_command": [ - "return-code=any python -mpip uninstall -y qiskit-terra", + "return-code=any python -mpip uninstall -y qiskit", "return-code=any python -mpip uninstall -y qiskit-aqua", "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ "python -mpip install -U scikit-build", - "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit", "pip install git+https://github.com/Qiskit/qiskit-aqua", "pip install pyscf", "pip install matplotlib", @@ -101,7 +101,7 @@ // }, //"matrix": { - // "pip+qiskit-terra": [""], + // "pip+qiskit": [""], //}, // Combinations of libraries/python versions can be excluded/included diff --git a/test/asv.linux.cuda.conf.json b/test/asv.linux.cuda.conf.json index d034764dcd..317c8842c7 100644 --- a/test/asv.linux.cuda.conf.json +++ b/test/asv.linux.cuda.conf.json @@ -33,18 +33,18 @@ "install_command": [ "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit', True)\"", "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info', True)\"", - "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit", "pip install git+https://github.com/Qiskit/qiskit-aqua", "python -mpip install {wheel_file}" ], "uninstall_command": [ - "return-code=any python -mpip uninstall -y qiskit-terra", + "return-code=any python -mpip uninstall -y qiskit", "return-code=any python -mpip uninstall -y qiskit-aqua", "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ "python -mpip install -U scikit-build", - "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit", "pip install git+https://github.com/Qiskit/qiskit-aqua", "pip install pyscf", "pip install matplotlib", @@ -101,7 +101,7 @@ // }, //"matrix": { - // "pip+qiskit-terra": [""], + // "pip+qiskit": [""], //}, // Combinations of libraries/python versions can be excluded/included diff --git a/test/benchmark/simulator_benchmark.py b/test/benchmark/simulator_benchmark.py index c7cd605486..bf1230a53f 100644 --- a/test/benchmark/simulator_benchmark.py +++ b/test/benchmark/simulator_benchmark.py @@ -179,7 +179,7 @@ def add_expval(base, num_terms): param_binds = {} for param in circuit.parameters: param_binds[param] = np.random.random() - circuit = circuit.bind_parameters(param_binds) + circuit = circuit.assign_parameters(param_binds) simulator = self.simulators[runtime] if measure == self.MEASUREMENT_SAMPLING: diff --git a/test/terra/backends/aer_simulator/test_algorithms.py b/test/terra/backends/aer_simulator/test_algorithms.py index 4c99576f59..337f993e63 100644 --- a/test/terra/backends/aer_simulator/test_algorithms.py +++ b/test/terra/backends/aer_simulator/test_algorithms.py @@ -123,7 +123,8 @@ def test_extended_stabilizer_sparse_output_probs(self): for i in range(1, nqubits): circ.cx(i - 1, i) circ.measure_all() - circ = transpile(circ, backend) + + # circ = transpile(circ, backend) target = { nqubits * "0": shots * (0.5 + sqrt(2) / 4.0), diff --git a/test/terra/backends/aer_simulator/test_auto_method.py b/test/terra/backends/aer_simulator/test_auto_method.py index 70fcb0d175..53adc9fb66 100644 --- a/test/terra/backends/aer_simulator/test_auto_method.py +++ b/test/terra/backends/aer_simulator/test_auto_method.py @@ -48,7 +48,7 @@ class TestSimulationMethod(SimulatorTestCase): # --------------------------------------------------------------------- def test_auto_method_clifford_circuits(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Test circuits backend = self.backend() shots = 100 @@ -59,7 +59,7 @@ def test_auto_method_clifford_circuits(self): self.compare_result_metadata(result, circuits, "method", "stabilizer") def test_auto_method_clifford_circuits_and_reset_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Test noise model noise_circs = [Reset(), IGate()] noise_probs = [0.5, 0.5] @@ -69,7 +69,7 @@ def test_auto_method_clifford_circuits_and_reset_noise(self): backend = self.backend(noise_model=noise_model) # Test circuits - shots = 100 + shots = 4 circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) result = backend.run(circuits, shots=shots).result() success = getattr(result, "success", False) @@ -77,7 +77,7 @@ def test_auto_method_clifford_circuits_and_reset_noise(self): self.compare_result_metadata(result, circuits, "method", "stabilizer") def test_auto_method_clifford_circuits_and_pauli_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Noise Model error = pauli_error([["XX", 0.5], ["II", 0.5]]) noise_model = NoiseModel() @@ -85,15 +85,31 @@ def test_auto_method_clifford_circuits_and_pauli_noise(self): backend = self.backend(noise_model=noise_model) # Test circuits - shots = 100 + shots = 4 circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) result = backend.run(circuits, shots=shots).result() success = getattr(result, "success", False) self.assertTrue(success) self.compare_result_metadata(result, circuits, "method", "stabilizer") + def test_auto_method_clifford_circuits_and_pauli_noise_with_many_shots(self): + """Test density_matrix method is used for Clifford circuit""" + # Noise Model + error = pauli_error([["XX", 0.5], ["II", 0.5]]) + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(error, ["cz", "cx"]) + backend = self.backend(noise_model=noise_model) + + # Test circuits + shots = 1000 + circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) + result = backend.run(circuits, shots=shots).result() + success = getattr(result, "success", False) + self.assertTrue(success) + self.compare_result_metadata(result, circuits, "method", "density_matrix") + def test_auto_method_clifford_circuits_and_unitary_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test density_matrix method is used for Clifford circuit""" # Noise Model error = mixed_unitary_error( [(Pauli("XX").to_matrix(), 0.5), (Pauli("II").to_matrix(), 0.5)] @@ -110,7 +126,7 @@ def test_auto_method_clifford_circuits_and_unitary_noise(self): self.compare_result_metadata(result, circuits, "method", "density_matrix") def test_auto_method_clifford_circuits_and_kraus_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test density_matrix method is used for Clifford circuit""" # Noise Model error = amplitude_damping_error(0.5) noise_model = NoiseModel() diff --git a/test/terra/backends/aer_simulator/test_conditional.py b/test/terra/backends/aer_simulator/test_conditional.py index 13f3ccb5b7..c5ec4e1ed1 100644 --- a/test/terra/backends/aer_simulator/test_conditional.py +++ b/test/terra/backends/aer_simulator/test_conditional.py @@ -17,6 +17,8 @@ from test.terra.reference import ref_conditionals from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods +from qiskit import QuantumCircuit + @ddt class TestConditionalGates(SimulatorTestCase): @@ -310,3 +312,71 @@ def test_conditional_superop_132bit(self, method, device): result = backend.run(circuits, shots=shots).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, hex_counts=False, delta=0) + + +@ddt +class TestConditionalReset(SimulatorTestCase): + """AerSimulator conditional reset tests.""" + + SUPPORTED_METHODS = [ + "automatic", + "statevector", + "density_matrix", + "matrix_product_state", + "tensor_network", + ] + + # --------------------------------------------------------------------- + # Test conditional + # --------------------------------------------------------------------- + @supported_methods(SUPPORTED_METHODS) + def test_conditional_reset_1bit(self, method, device): + """Test conditional reset on 1-bit conditional register.""" + shots = 100 + backend = self.backend(method=method, device=device) + backend.set_options(max_parallel_experiments=0) + + circuits = ref_conditionals.conditional_circuits_1bit( + final_measure=True, conditional_type="reset" + ) + targets = ref_conditionals.conditional_counts_1bit_with_reset(shots) + result = backend.run(circuits, shots=shots).result() + self.assertSuccess(result) + self.compare_counts(result, circuits, targets, delta=0) + + +@ddt +class TestConditionalDiagonal(SimulatorTestCase): + """AerSimulator conditional diagonal tests.""" + + # --------------------------------------------------------------------- + # Test conditional + # --------------------------------------------------------------------- + def test_conditional_diagonal(self): + """Test conditional diagonal with statevector.""" + shots = 100 + backend = self.backend(method="statevector", device="CPU") + backend.set_options(max_parallel_experiments=0) + + circuit = QuantumCircuit(4, 4) + for i in range(1, 4): + circuit.h(i) + circuit.save_statevector(label="base") + + circuit0 = QuantumCircuit(4, 4) + for i in range(1, 4): + circuit0.h(i) + circuit0.diagonal([-1, -1], [1]).c_if(circuit0.clbits[0], 0) + circuit0.save_statevector(label="diff") + + circuit1 = QuantumCircuit(4, 4) + for i in range(1, 4): + circuit1.h(i) + circuit1.diagonal([-1, -1], [1]).c_if(circuit1.clbits[0], 1) + circuit1.save_statevector(label="equal") + + result = backend.run([circuit, circuit0, circuit1], shots=1).result() + self.assertSuccess(result) + + self.assertNotEqual(result.data(circuit)["base"], result.data(circuit0)["diff"]) + self.assertEqual(result.data(circuit)["base"], result.data(circuit1)["equal"]) diff --git a/test/terra/backends/aer_simulator/test_control_flow.py b/test/terra/backends/aer_simulator/test_control_flow.py index 34847dccf9..89a8b07713 100644 --- a/test/terra/backends/aer_simulator/test_control_flow.py +++ b/test/terra/backends/aer_simulator/test_control_flow.py @@ -21,6 +21,7 @@ from qiskit import QuantumCircuit, transpile from qiskit.circuit import Parameter, Qubit, Clbit, QuantumRegister, ClassicalRegister from qiskit.circuit.controlflow import * +from qiskit.circuit.classical import expr, types from qiskit_aer.library.default_qubits import default_qubits from qiskit_aer.library.control_flow_instructions import AerMark, AerJump @@ -53,7 +54,7 @@ def add_jump(self, circ, jump_to, clbit=None, value=0): instr.c_if(clbit, value) return circ.append(instr, qubits) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_jump_always(self, method): backend = self.backend(method=method) @@ -75,7 +76,7 @@ def test_jump_always(self, method): self.assertEqual(len(counts), 1) self.assertIn("0000", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_jump_conditional(self, method): backend = self.backend(method=method) @@ -97,7 +98,7 @@ def test_jump_conditional(self, method): self.assertEqual(len(counts), 1) self.assertIn("0000 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_no_jump_conditional(self, method): backend = self.backend(method=method) @@ -118,7 +119,7 @@ def test_no_jump_conditional(self, method): counts = result.get_counts() self.assertNotEqual(len(counts), 1) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_invalid_jump(self, method): logging.disable(level=logging.WARN) @@ -141,7 +142,7 @@ def test_invalid_jump(self, method): logging.disable(level=logging.NOTSET) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_duplicated_mark(self, method): logging.disable(level=logging.WARN) @@ -164,7 +165,7 @@ def test_duplicated_mark(self, method): logging.disable(level=logging.NOTSET) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_if_true_body_builder(self, method): backend = self.backend(method=method) @@ -188,7 +189,7 @@ def test_if_true_body_builder(self, method): self.assertEqual(len(counts), 1) self.assertIn("0001 1", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_if_else_body_builder(self, method): backend = self.backend(method=method) @@ -213,7 +214,7 @@ def test_if_else_body_builder(self, method): self.assertEqual(len(counts), 1) self.assertIn("0000 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_for_loop_builder(self, method): backend = self.backend(method=method) @@ -239,7 +240,7 @@ def test_for_loop_builder(self, method): self.assertEqual(len(counts), 1) self.assertIn("01100", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_for_loop_builder_no_loop_variable(self, method): backend = self.backend(method=method) @@ -265,7 +266,7 @@ def test_for_loop_builder_no_loop_variable(self, method): self.assertEqual(len(counts), 1) self.assertIn("01010", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_for_loop_break_builder(self, method): backend = self.backend(method=method) @@ -308,7 +309,7 @@ def test_for_loop_break_builder(self, method): self.assertEqual(len(counts), 1) self.assertIn("11100 1", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_for_loop_continue_builder(self, method): backend = self.backend(method=method) @@ -370,7 +371,7 @@ def test_for_loop_continue_builder(self, method): self.assertEqual(len(counts), 1) self.assertIn("11110 0 1 0 0 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_while_loop_no_iteration(self, method): backend = self.backend(method=method) @@ -389,7 +390,7 @@ def test_while_loop_no_iteration(self, method): self.assertEqual(len(counts), 1) self.assertIn("0 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_while_loop_single_iteration(self, method): backend = self.backend(method=method) @@ -420,7 +421,7 @@ def test_while_loop_single_iteration(self, method): self.assertEqual(len(counts), 1) self.assertIn("10 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_while_loop_double_iterations(self, method): backend = self.backend(method=method) @@ -451,7 +452,7 @@ def test_while_loop_double_iterations(self, method): self.assertEqual(len(counts), 1) self.assertIn("01 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_while_loop_continue(self, method): backend = self.backend(method=method) @@ -485,7 +486,7 @@ def test_while_loop_continue(self, method): self.assertEqual(len(counts), 1) self.assertIn("0 0", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_nested_loop(self, method): backend = self.backend(method=method) @@ -512,7 +513,7 @@ def test_nested_loop(self, method): self.assertEqual(len(counts), 1) self.assertIn("011", counts) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_while_loop_last(self, method): backend = self.backend(method=method) @@ -526,7 +527,7 @@ def test_while_loop_last(self, method): result = backend.run(circ, method=method).result() self.assertSuccess(result) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_no_invalid_nested_reordering(self, method): """Test that the jump/mark system doesn't allow nested conditional marks to jump incorrectly relative to their outer marks. Regression test of gh-1665.""" @@ -548,7 +549,7 @@ def test_no_invalid_nested_reordering(self, method): self.assertSuccess(result) self.assertEqual(result.get_counts(), {"110": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_no_invalid_reordering_if(self, method): """Test that the jump/mark system doesn't allow an unrelated operation to jump inside a conditional statement.""" @@ -574,7 +575,7 @@ def test_no_invalid_reordering_if(self, method): self.assertSuccess(result) self.assertEqual(result.get_counts(), {"010": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_no_invalid_reordering_while(self, method): """Test that the jump/mark system doesn't allow an unrelated operation to jump inside a conditional statement.""" @@ -600,7 +601,7 @@ def test_no_invalid_reordering_while(self, method): self.assertSuccess(result) self.assertEqual(result.get_counts(), {"010": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_transpile_break_and_continue_loop(self, method): """Test that transpiler can transpile break_loop and continue_loop with AerSimulator""" @@ -631,7 +632,7 @@ def test_transpile_break_and_continue_loop(self, method): result = backend.run(transpiled, method=method, shots=100).result() self.assertEqual(result.get_counts(), {"1": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_switch_clbit(self, method): """Test that a switch statement can be constructed with a bit as a condition.""" @@ -680,7 +681,7 @@ def test_switch_clbit(self, method): self.assertSuccess(ret1) self.assertEqual(ret1.get_counts(), ret1_expected.get_counts()) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_switch_register(self, method): """Test that a switch statement can be constructed with a register as a condition.""" @@ -741,7 +742,7 @@ def test_switch_register(self, method): self.assertSuccess(ret3) self.assertEqual(ret3.get_counts(), {"011 11": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_switch_with_default(self, method): """Test that a switch statement can be constructed with a default case at the end.""" @@ -802,7 +803,7 @@ def test_switch_with_default(self, method): self.assertSuccess(ret3) self.assertEqual(ret3.get_counts(), {"111 11": 100}) - @data("statevector", "density_matrix", "matrix_product_state") + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") def test_switch_multiple_cases_to_same_block(self, method): """Test that it is possible to add multiple cases that apply to the same block, if they are given as a compound value. This is an allowed special case of block fall-through.""" @@ -863,3 +864,326 @@ def test_switch_multiple_cases_to_same_block(self, method): ret3 = backend.run(qc3, shots=100).result() self.assertSuccess(ret3) self.assertEqual(ret3.get_counts(), {"011 11": 100}) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_switch_transpilation(self, method): + """Test swtich test cases can be transpiled""" + + backend = self.backend(method=method, seed_simulator=1) + + qubit0 = Qubit() + qubit1 = Qubit() + qubit2 = Qubit() + + creg = ClassicalRegister(2) + qc = QuantumCircuit([qubit0, qubit1, qubit2], creg) + + with qc.switch(creg) as case: + with case(0): + qc.x(0) + with case(1): + qc.x(1) + with case(case.DEFAULT): + qc.x(2) + + qc.measure_all() + + transpiled = transpile(qc, backend) + + ret0 = backend.run(transpiled, shots=100).result() + self.assertSuccess(ret0) + self.assertEqual(ret0.get_counts(), {"001 00": 100}) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_switch_register_with_classical_expression(self, method): + """Test that a switch statement can be constructed with a register as a condition.""" + + backend = self.backend(method=method, seed_simulator=1) + + qubit0 = Qubit() + qubit1 = Qubit() + qubit2 = Qubit() + creg = ClassicalRegister(2) + case1 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + case1.x(0) + case2 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + case2.x(1) + case3 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + case3.x(2) + + op = SwitchCaseOp(expr.lift(creg), [(0, case1), (1, case2), (2, case3)]) + + qc0 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + qc0.measure(0, creg[0]) + qc0.append(op, [qubit0, qubit1, qubit2], creg) + qc0.measure_all() + + ret0 = backend.run(qc0, shots=100).result() + self.assertSuccess(ret0) + self.assertEqual(ret0.get_counts(), {"001 00": 100}) + + qc1 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + qc1.x(0) + qc1.measure(0, creg[0]) + qc1.append(op, [qubit0, qubit1, qubit2], creg) + qc1.measure_all() + + ret1 = backend.run(qc1, shots=1).result() + self.assertSuccess(ret1) + self.assertEqual(ret1.get_counts(), {"011 01": 1}) + + qc2 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + qc2.x(1) + qc2.measure(0, creg[0]) + qc2.measure(1, creg[1]) + qc2.append(op, [qubit0, qubit1, qubit2], creg) + qc2.measure_all() + + ret2 = backend.run(qc2, shots=100).result() + self.assertSuccess(ret2) + self.assertEqual(ret2.get_counts(), {"110 10": 100}) + + qc3 = QuantumCircuit([qubit0, qubit1, qubit2], creg) + qc3.x(0) + qc3.x(1) + qc3.measure(0, creg[0]) + qc3.measure(1, creg[1]) + qc3.append(op, [qubit0, qubit1, qubit2], creg) + qc3.measure_all() + + ret3 = backend.run(qc3, shots=100).result() + self.assertSuccess(ret3) + self.assertEqual(ret3.get_counts(), {"011 11": 100}) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_if_expr_true_body_builder(self, method): + """test expression with branch operation""" + backend = self.backend(method=method) + + # case creg==1 + qreg = QuantumRegister(4) + creg = ClassicalRegister(3, "test") + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.h(circ.qubits[1:4]) + circ.barrier() + circ.measure(0, 0) # 001 + + with circ.if_test(expr.equal(ClassicalRegister(3, "test"), 1)): + circ.h(circ.qubits[1:4]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0001 001", counts) + + # case creg==3 + qreg = QuantumRegister(4) + creg = ClassicalRegister(3, "test") + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.h(circ.qubits[1:4]) + circ.barrier() + circ.measure(0, 0) + circ.measure(0, 1) # 011 + + with circ.if_test(expr.equal(ClassicalRegister(3, "test"), 3)): + circ.h(circ.qubits[1:4]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0001 011", counts) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_if_expr_false_body_builder(self, method): + """test expression with branch operation""" + backend = self.backend(method=method) + + # case creg==1 + qreg = QuantumRegister(4) + creg = ClassicalRegister(3, "test") + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.h(circ.qubits[1:4]) + circ.barrier() + circ.measure(0, 0) # 001 + + with circ.if_test(expr.equal(ClassicalRegister(3, "test"), 2)) as else_: + circ.y(0) + with else_: + circ.h(circ.qubits[1:4]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0001 001", counts) + + # case creg==3 + qreg = QuantumRegister(4) + creg = ClassicalRegister(3, "test") + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.h(circ.qubits[1:4]) + circ.barrier() + circ.measure(0, 0) + circ.measure(0, 1) # 011 + + with circ.if_test(expr.equal(ClassicalRegister(3, "test"), 1)) as else_: + circ.y(0) + with else_: + circ.h(circ.qubits[1:4]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0001 011", counts) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_while_expr_loop_break(self, method): + backend = self.backend(method=method) + + qreg = QuantumRegister(1) + creg = ClassicalRegister(1) + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.measure(0, 0) + + circ_while = QuantumCircuit(qreg, creg) + circ_while.y(0) + circ_while.measure(0, 0) + circ_while.break_loop() + circ.while_loop(expr.Value(True, types.Bool()), circ_while, [0], [0]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0 0", counts) + + qreg = QuantumRegister(1) + creg = ClassicalRegister(1) + circ = QuantumCircuit(qreg, creg) + circ.y(0) + circ.measure(0, 0) + + circ_while = QuantumCircuit(qreg, creg) + circ_while.y(0) + circ_while.measure(0, 0) + circ_while.break_loop() + circ.while_loop(expr.Value(False, types.Bool()), circ_while, [0], [0]) + + circ.measure_all() + + result = backend.run(circ, method=method).result() + self.assertSuccess(result) + + counts = result.get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("1 1", counts) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_bit_and_operation(self, method): + """test bit-and operation""" + qr = QuantumRegister(7) + cr = ClassicalRegister(7) + qc = QuantumCircuit(qr, cr) + qc.x(0) + qc.x(2) + qc.measure(range(4), range(4)) # 0101 + qc.barrier() + b01 = expr.bit_and(cr[0], cr[1]) # 1 & 0 -> 0 + with qc.if_test(b01): + qc.x(4) # q4 -> 0 + + b02 = expr.bit_and(cr[0], cr[2]) # 1 & 1 -> 1 + with qc.if_test(b02): + qc.x(5) # q5 -> 0 + + b13 = expr.bit_and(cr[1], cr[3]) # 0 & 0 -> 0 + with qc.if_test(b13): + qc.x(6) # q6 -> 0 + + qc.measure(range(7), range(7)) # 0100101 + + backend = self.backend(method=method) + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0100101", counts) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_bit_or_operation(self, method): + """test bit-or operation""" + qr = QuantumRegister(7) + cr = ClassicalRegister(7) + qc = QuantumCircuit(qr, cr) + qc.x(0) + qc.x(2) + qc.measure(range(4), range(4)) # 0101 + qc.barrier() + b01 = expr.bit_or(cr[0], cr[1]) # 1 & 0 -> 1 + with qc.if_test(b01): + qc.x(4) # q4 -> 1 + + b02 = expr.bit_or(cr[0], cr[2]) # 1 & 1 -> 1 + with qc.if_test(b02): + qc.x(5) # q5 -> 0 + + b13 = expr.bit_or(cr[1], cr[3]) # 0 & 0 -> 0 + with qc.if_test(b13): + qc.x(6) # q6 -> 0 + + qc.measure(range(7), range(7)) # 0110101 + + backend = self.backend(method=method) + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0110101", counts) + + @data("statevector", "density_matrix", "matrix_product_state", "stabilizer") + def test_bit_xor_operation(self, method): + """test bit-or operation""" + qr = QuantumRegister(7) + cr = ClassicalRegister(7) + qc = QuantumCircuit(qr, cr) + qc.x(0) + qc.x(2) + qc.measure(range(4), range(4)) # 0101 + qc.barrier() + b01 = expr.bit_xor(cr[0], cr[1]) # 1 & 0 -> 1 + with qc.if_test(b01): + qc.x(4) # q4 -> 1 + + b02 = expr.bit_xor(cr[0], cr[2]) # 1 & 1 -> 0 + with qc.if_test(b02): + qc.x(5) # q5 -> 0 + + b13 = expr.bit_xor(cr[1], cr[3]) # 0 & 0 -> 0 + with qc.if_test(b13): + qc.x(6) # q6 -> 0 + + qc.measure(range(7), range(7)) # 0010101 + + backend = self.backend(method=method) + counts = backend.run(qc).result().get_counts() + self.assertEqual(len(counts), 1) + self.assertIn("0010101", counts) diff --git a/test/terra/backends/aer_simulator/test_executors.py b/test/terra/backends/aer_simulator/test_executors.py index 068126f4b0..28fc99d57c 100644 --- a/test/terra/backends/aer_simulator/test_executors.py +++ b/test/terra/backends/aer_simulator/test_executors.py @@ -13,13 +13,18 @@ AerSimualtor options tests """ import logging +import json from math import ceil import concurrent.futures +import pickle +import tempfile from ddt import ddt from qiskit import QuantumCircuit, transpile from qiskit.circuit.random import random_circuit +from qiskit.circuit.library import QuantumVolume from qiskit.quantum_info import Statevector +from qiskit_aer.noise.noise_model import AerJSONEncoder from test.terra.reference import ref_kraus_noise from qiskit_aer.jobs import AerJob, AerJobSet from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods @@ -56,6 +61,32 @@ def run_random_circuits(backend, shots=None, **run_options): return result, circuits, targets +class TestResultSerialization(SimulatorTestCase): + """Test seriallization of AerJob""" + + def test_aer_job_json_dump(self): + circuit = QuantumVolume(4, seed=111) + circuit.measure_all() + backend = self.backend(method="statevector") + result = backend.run(transpile(circuit, backend)).result() + data = json.dumps(result, cls=AerJSONEncoder) + result_copy = json.loads(data) + self.compare_counts(result, [circuit], [result_copy["results"][0]["data"]["counts"]]) + + def test_aer_job_picklable(self): + circuit = QuantumVolume(4, seed=111) + circuit.measure_all() + backend = self.backend(method="statevector") + result = backend.run(transpile(circuit, backend)).result() + + with tempfile.TemporaryFile() as f: + pickle.dump(result, f) + f.seek(0) + result_copy = pickle.load(f) + + self.assertEqual(result.get_counts(), result_copy.get_counts()) + + class CBFixture(SimulatorTestCase): """Extension tests for Aerbackend with cluster backend""" diff --git a/test/terra/backends/aer_simulator/test_fusion.py b/test/terra/backends/aer_simulator/test_fusion.py index d2d5c42289..bf281e4324 100644 --- a/test/terra/backends/aer_simulator/test_fusion.py +++ b/test/terra/backends/aer_simulator/test_fusion.py @@ -485,7 +485,7 @@ def test_fusion_two_qubits(self): for param in circuit.parameters: param_binds[param] = np.random.random() - circuit = transpile(circuit.bind_parameters(param_binds), backend, optimization_level=0) + circuit = transpile(circuit.assign_parameters(param_binds), backend, optimization_level=0) backend_options = self.fusion_options(enabled=True, threshold=1) backend_options["fusion_verbose"] = True diff --git a/test/terra/backends/aer_simulator/test_initialize.py b/test/terra/backends/aer_simulator/test_initialize.py index 739a77f709..015c971c8d 100644 --- a/test/terra/backends/aer_simulator/test_initialize.py +++ b/test/terra/backends/aer_simulator/test_initialize.py @@ -224,3 +224,15 @@ def test_initialize_with_int_twice(self, method, device): actual = backend.run(circ).result().get_statevector(circ) self.assertAlmostEqual(actual[5], 1) + + @supported_methods(SUPPORTED_METHODS) + def test_initialize_with_global_phase(self, method, device): + """Test AerSimulator initialize with global phase""" + backend = self.backend(method=method, device=device) + circ = QuantumCircuit(2) + circ.global_phase = np.pi + circ.initialize([1, 0, 0, 0]) + circ.x(0) + circ.save_statevector() + actual = backend.run(circ).result().get_statevector(circ) + self.assertAlmostEqual(actual[1], -1) diff --git a/test/terra/backends/aer_simulator/test_measure.py b/test/terra/backends/aer_simulator/test_measure.py index fd39d68042..aaf40b598e 100644 --- a/test/terra/backends/aer_simulator/test_measure.py +++ b/test/terra/backends/aer_simulator/test_measure.py @@ -142,7 +142,8 @@ def test_measure_sampling_with_quantum_noise(self, method, device): targets = ref_measure.measure_counts_deterministic(shots) result = backend.run(circuits, shots=shots).result() self.assertSuccess(result) - sampling = method == "density_matrix" or method == "tensor_network" + method_used = result.results[0].metadata.get("method") + sampling = method_used == "density_matrix" or method_used == "tensor_network" self.compare_result_metadata(result, circuits, "measure_sampling", sampling) # --------------------------------------------------------------------- diff --git a/test/terra/backends/aer_simulator/test_noise.py b/test/terra/backends/aer_simulator/test_noise.py index 9255bc8868..5e4a4c579c 100644 --- a/test/terra/backends/aer_simulator/test_noise.py +++ b/test/terra/backends/aer_simulator/test_noise.py @@ -15,6 +15,7 @@ from ddt import ddt from qiskit_aer import noise +import numpy as np import qiskit.quantum_info as qi from qiskit import transpile @@ -69,6 +70,20 @@ def test_readout_noise(self, method, device): self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) + @supported_methods(ALL_METHODS) + def test_readout_noise_without_basis_gates(self, method, device): + """Test simulation with classical readout error noise model w/o basis gates.""" + backend = self.backend(method=method, device=device) + noise_model = noise.NoiseModel() + noise_model.add_readout_error(np.array([[0.9, 0.1], [0.1, 0.9]]), [0]) + backend.set_options(noise_model=noise_model) + circ = QuantumCircuit(1, 1) + circ.reset(0) + circ.measure(0, 0) + circ = transpile(circ, backend) + result = backend.run(circ, shots=1).result() + self.assertSuccess(result) + @supported_methods(ALL_METHODS) def test_pauli_gate_noise(self, method, device): """Test simulation with Pauli gate error noise model.""" diff --git a/test/terra/backends/aer_simulator/test_options.py b/test/terra/backends/aer_simulator/test_options.py index 51dff7d4be..ca63207181 100644 --- a/test/terra/backends/aer_simulator/test_options.py +++ b/test/terra/backends/aer_simulator/test_options.py @@ -46,7 +46,7 @@ def test_seed_simulator_option_measure(self, method, device): qc.h([0, 1]) qc.reset(0) qc.measure_all() - qc = transpile(qc, backend) + qc = transpile(qc, backend, optimization_level=0) counts1 = backend.run(qc).result().get_counts(0) counts2 = backend.run(qc).result().get_counts(0) @@ -71,7 +71,7 @@ def test_seed_simulator_run_option_measure(self, method, device): qc.h([0, 1]) qc.reset(0) qc.measure_all() - qc = transpile(qc, backend) + qc = transpile(qc, backend, optimization_level=0) seed = 1234 counts1 = backend.run(qc, seed_simulator=seed).result().get_counts(0) counts2 = backend.run(qc, seed_simulator=seed).result().get_counts(0) diff --git a/test/terra/backends/aer_simulator/test_thread_management.py b/test/terra/backends/aer_simulator/test_thread_management.py index 003cb92372..60154e8c25 100644 --- a/test/terra/backends/aer_simulator/test_thread_management.py +++ b/test/terra/backends/aer_simulator/test_thread_management.py @@ -147,7 +147,9 @@ def test_parallel_defaults_single_ideal(self): def test_parallel_defaults_single_noise(self): """Test parallel thread assignment defaults""" backend = self.backend( - noise_model=self.dummy_noise_model(), **self.backend_options_parallel() + method="statevector", + noise_model=self.dummy_noise_model(), + **self.backend_options_parallel(), ) max_threads = self.available_threads() @@ -209,7 +211,9 @@ def test_parallel_defaults_multi_ideal(self): def test_parallel_defaults_multi_noise(self): """Test parallel thread assignment defaults""" backend = self.backend( - noise_model=self.dummy_noise_model(), **self.backend_options_parallel() + method="statevector", + noise_model=self.dummy_noise_model(), + **self.backend_options_parallel(), ) max_threads = self.available_threads() @@ -295,7 +299,9 @@ def test_parallel_thread_assignment(self, custom_max_threads): # Test single circuit, with noise # Parallel experiments should always be 1 # parallel shots should be greater than 1 - backend = self.backend(noise_model=self.dummy_noise_model(), **parallel_opts) + backend = self.backend( + method="statevector", noise_model=self.dummy_noise_model(), **parallel_opts + ) circuits = self.dummy_circuit(1) result = backend.run(circuits, shots=shots).result() for threads in self.threads_used(result): @@ -531,6 +537,7 @@ def test_parallel_shot_thread_multi_noise(self): max_threads = self.available_threads() backend = self.backend( + method="statevector", noise_model=self.dummy_noise_model(), **self.backend_options_parallel(shot_threads=max_threads), ) diff --git a/test/terra/backends/test_parameterized_qobj.py b/test/terra/backends/test_parameterized_qobj.py index 4ca2c809ca..e08c697ccf 100644 --- a/test/terra/backends/test_parameterized_qobj.py +++ b/test/terra/backends/test_parameterized_qobj.py @@ -355,7 +355,7 @@ def test_run_path_with_truncation(self): param_map = {theta: [0.1 * i for i in range(3)]} param_sets = [{theta: 0.1 * i} for i in range(3)] - resolved_circuits = [circuit.bind_parameters(param_set) for param_set in param_sets] + resolved_circuits = [circuit.assign_parameters(param_set) for param_set in param_sets] result = backend.run(circuit, parameter_binds=[param_map]).result() self.assertSuccess(result) @@ -480,7 +480,7 @@ def test_global_phase_parameters(self): circs = [] for v in [1, 2, 3]: - circs.append(circ.bind_parameters({theta: v})) + circs.append(circ.assign_parameters({theta: v})) expected = backend.run(circs, shots=10, seed_simulator=100).result() diff --git a/test/terra/backends/test_runtime_parameterization.py b/test/terra/backends/test_runtime_parameterization.py index 353d7178da..e2c8af659f 100644 --- a/test/terra/backends/test_runtime_parameterization.py +++ b/test/terra/backends/test_runtime_parameterization.py @@ -456,7 +456,7 @@ def test_run_path_with_truncation(self, method, device): param_map = {theta: [0.1 * i for i in range(3)]} param_sets = [{theta: 0.1 * i} for i in range(3)] - resolved_circuits = [circuit.bind_parameters(param_set) for param_set in param_sets] + resolved_circuits = [circuit.assign_parameters(param_set) for param_set in param_sets] result = backend.run( circuit, diff --git a/test/terra/common.py b/test/terra/common.py index e7092df517..7663533e7f 100644 --- a/test/terra/common.py +++ b/test/terra/common.py @@ -18,6 +18,7 @@ import logging import os import warnings +import unittest from enum import Enum from itertools import repeat from math import pi @@ -30,7 +31,7 @@ from qiskit_aer import __path__ as main_path from qiskit.quantum_info import Operator, Statevector from qiskit.quantum_info.operators.predicates import matrix_equal -from qiskit.test.base import FullQiskitTestCase +from .decorators import enforce_subclasses_call class Path(Enum): @@ -42,12 +43,146 @@ class Path(Enum): EXAMPLES = os.path.join(MAIN, "../examples") -class QiskitAerTestCase(FullQiskitTestCase): +@enforce_subclasses_call(["setUp", "setUpClass", "tearDown", "tearDownClass"]) +class BaseQiskitAerTestCase(unittest.TestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.__setup_called = False + self.__teardown_called = False + + def setUp(self): + super().setUp() + if self.__setup_called: + raise ValueError( + "In File: %s\n" + "TestCase.setUp was already called. Do not explicitly call " + "setUp from your tests. In your own setUp, use super to call " + "the base setUp." % (sys.modules[self.__class__.__module__].__file__,) + ) + self.__setup_called = True + + def tearDown(self): + super().tearDown() + if self.__teardown_called: + raise ValueError( + "In File: %s\n" + "TestCase.tearDown was already called. Do not explicitly call " + "tearDown from your tests. In your own tearDown, use super to " + "call the base tearDown." % (sys.modules[self.__class__.__module__].__file__,) + ) + self.__teardown_called = True + + @staticmethod + def _get_resource_path(filename, path=Path.TEST): + """Get the absolute path to a resource. + + Args: + filename (string): filename or relative path to the resource. + path (Path): path used as relative to the filename. + + Returns: + str: the absolute path to the resource. + """ + return os.path.normpath(os.path.join(path.value, filename)) + + def assertDictAlmostEqual( + self, dict1, dict2, delta=None, msg=None, places=None, default_value=0 + ): + """Assert two dictionaries with numeric values are almost equal. + + Fail if the two dictionaries are unequal as determined by + comparing that the difference between values with the same key are + not greater than delta (default 1e-8), or that difference rounded + to the given number of decimal places is not zero. If a key in one + dictionary is not in the other the default_value keyword argument + will be used for the missing value (default 0). If the two objects + compare equal then they will automatically compare almost equal. + + Args: + dict1 (dict): a dictionary. + dict2 (dict): a dictionary. + delta (number): threshold for comparison (defaults to 1e-8). + msg (str): return a custom message on failure. + places (int): number of decimal places for comparison. + default_value (number): default value for missing keys. + + Raises: + TypeError: if the arguments are not valid (both `delta` and + `places` are specified). + AssertionError: if the dictionaries are not almost equal. + """ + + error_msg = dicts_almost_equal(dict1, dict2, delta, places, default_value) + + if error_msg: + msg = self._formatMessage(msg, error_msg) + raise self.failureException(msg) + + +def dicts_almost_equal(dict1, dict2, delta=None, places=None, default_value=0): + """Test if two dictionaries with numeric values are almost equal. + + Fail if the two dictionaries are unequal as determined by + comparing that the difference between values with the same key are + not greater than delta (default 1e-8), or that difference rounded + to the given number of decimal places is not zero. If a key in one + dictionary is not in the other the default_value keyword argument + will be used for the missing value (default 0). If the two objects + compare equal then they will automatically compare almost equal. + + Args: + dict1 (dict): a dictionary. + dict2 (dict): a dictionary. + delta (number): threshold for comparison (defaults to 1e-8). + places (int): number of decimal places for comparison. + default_value (number): default value for missing keys. + + Raises: + TypeError: if the arguments are not valid (both `delta` and + `places` are specified). + + Returns: + String: Empty string if dictionaries are almost equal. A description + of their difference if they are deemed not almost equal. + """ + + def valid_comparison(value): + """compare value to delta, within places accuracy""" + if places is not None: + return round(value, places) == 0 + else: + return value < delta + + # Check arguments. + if dict1 == dict2: + return "" + if places is not None: + if delta is not None: + raise TypeError("specify delta or places not both") + msg_suffix = " within %s places" % places + else: + delta = delta or 1e-8 + msg_suffix = " within %s delta" % delta + + # Compare all keys in both dicts, populating error_msg. + error_msg = "" + for key in set(dict1.keys()) | set(dict2.keys()): + val1 = dict1.get(key, default_value) + val2 = dict2.get(key, default_value) + if not valid_comparison(abs(val1 - val2)): + error_msg += f"({safe_repr(key)}: {safe_repr(val1)} != {safe_repr(val2)}), " + + if error_msg: + return error_msg[:-2] + msg_suffix + else: + return "" + + +class QiskitAerTestCase(BaseQiskitAerTestCase): """Helper class that contains common functionality.""" def setUp(self): super().setUp() - self.useFixture(fixtures.Timeout(240, gentle=False)) @classmethod def setUpClass(cls): diff --git a/test/terra/decorators.py b/test/terra/decorators.py index c5d19a1426..faed729d68 100644 --- a/test/terra/decorators.py +++ b/test/terra/decorators.py @@ -18,9 +18,12 @@ import unittest from qiskit import QuantumCircuit, execute +from qiskit.utils import wrap_method from qiskit_aer import AerProvider, AerSimulator +from typing import Union, Callable, Type, Iterable + def is_method_available(backend, method): """Check if input method is available for the qasm simulator.""" @@ -94,3 +97,99 @@ def _deprecated_method(self, *args, **kwargs): method(self, *args, **kwargs) return _deprecated_method + + +def enforce_subclasses_call( + methods: Union[str, Iterable[str]], attr: str = "_enforce_subclasses_call_cache" +) -> Callable[[Type], Type]: + """Class decorator which enforces that if any subclasses define on of the ``methods``, they must + call ``super().()`` or face a ``ValueError`` at runtime. + + This is unlikely to be useful for concrete test classes, who are not normally subclassed. It + should not be used on user-facing code, because it prevents subclasses from being free to + override parent-class behavior, even when the parent-class behavior is not needed. + + This adds behavior to the ``__init__`` and ``__init_subclass__`` methods of the class, in + addition to the named methods of this class and all subclasses. The checks could be averted in + grandchildren if a child class overrides ``__init_subclass__`` without up-calling the decorated + class's method, though this would typically break inheritance principles. + + Arguments: + methods: + Names of the methods to add the enforcement to. These do not necessarily need to be + defined in the class body, provided they are somewhere in the method-resolution tree. + + attr: + The attribute which will be added to all instances of this class and subclasses, in + order to manage the call enforcement. This can be changed to avoid clashes. + + Returns: + A decorator, which returns its input class with the class with the relevant methods modified + to include checks, and injection code in the ``__init_subclass__`` method. + """ + + methods = {methods} if isinstance(methods, str) else set(methods) + + def initialize_call_memory(self, *_args, **_kwargs): + """Add the extra attribute used for tracking the method calls.""" + setattr(self, attr, set()) + + def save_call_status(name): + """Decorator, whose return saves the fact that the top-level method call occurred.""" + + def out(self, *_args, **_kwargs): + getattr(self, attr).add(name) + + return out + + def clear_call_status(name): + """Decorator, whose return clears the call status of the method ``name``. This prepares the + call tracking for the child class's method call.""" + + def out(self, *_args, **_kwargs): + getattr(self, attr).discard(name) + + return out + + def enforce_call_occurred(name): + """Decorator, whose return checks that the top-level method call occurred, and raises + ``ValueError`` if not. Concretely, this is an assertion that ``save_call_status`` ran.""" + + def out(self, *_args, **_kwargs): + cache = getattr(self, attr) + if name not in cache: + classname = self.__name__ if isinstance(self, type) else type(self).__name__ + raise ValueError( + f"Parent '{name}' method was not called by '{classname}.{name}'." + f" Ensure you have put in calls to 'super().{name}()'." + ) + + return out + + def wrap_subclass_methods(cls): + """Wrap all the ``methods`` of ``cls`` with the call-tracking assertions that the top-level + versions of the methods were called (likely via ``super()``).""" + # Only wrap methods who are directly defined in this class; if we're resolving to a method + # higher up the food chain, then it will already have been wrapped. + for name in set(cls.__dict__) & methods: + wrap_method( + cls, + name, + before=clear_call_status(name), + after=enforce_call_occurred(name), + ) + + def decorator(cls): + # Add a class-level memory on, so class methods will work as well. Instances will override + # this on instantiation, to keep the "namespace" of class- and instance-methods separate. + initialize_call_memory(cls) + # Do the extra bits after the main body of __init__ so we can check we're not overwriting + # anything, and after __init_subclass__ in case the decorated class wants to influence the + # creation of the subclass's methods before we get to them. + wrap_method(cls, "__init__", after=initialize_call_memory) + for name in methods: + wrap_method(cls, name, before=save_call_status(name)) + wrap_method(cls, "__init_subclass__", after=wrap_subclass_methods) + return cls + + return decorator diff --git a/test/terra/expression/test_classical_expressions.py b/test/terra/expression/test_classical_expressions.py new file mode 100644 index 0000000000..fee05f7a6f --- /dev/null +++ b/test/terra/expression/test_classical_expressions.py @@ -0,0 +1,440 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2023. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Tests for utility functions to create device noise model. +""" + +from test.terra.common import QiskitAerTestCase + +from qiskit.providers.aer.backends.controller_wrappers import * + + +class TestClassicalExpressions(QiskitAerTestCase): + """Testing classical expressions""" + + def test_eval_uint(self): + """test eval_uint of uint and bool""" + self.assertEqual(AerUintValue(32, 0).eval_uint(""), 0) + self.assertEqual(AerUintValue(32, 1).eval_uint(""), 1) + self.assertEqual(AerUintValue(32, 10).eval_uint(""), 10) + + try: + AerBoolValue(False).eval_uint("") + self.fail("do not reach here") + except Exception: + pass + + try: + AerBoolValue(True).eval_uint("") + self.fail("do not reach here") + except Exception: + pass + + def test_eval_bool(self): + """test eval_bool of uint and bool""" + try: + AerUintValue(32, 0).eval_bool("") + self.fail("do not reach here") + except Exception: + pass + + try: + AerUintValue(32, 1).eval_bool("") + self.fail("do not reach here") + except Exception: + pass + + self.assertEqual(AerBoolValue(False).eval_bool(""), False) + self.assertEqual(AerBoolValue(True).eval_bool(""), True) + + def test_var(self): + """test AerVar""" + + # normal ordering + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("000"), 0) + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("001"), 1) + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("010"), 2) + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("011"), 3) + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("111"), 7) + + # custom ordering + self.assertEqual(AerVar(AerUint(3), [1, 0, 2]).eval_uint("000"), 0) + self.assertEqual(AerVar(AerUint(3), [1, 0, 2]).eval_uint("001"), 2) + + # overflow + self.assertEqual(AerVar(AerUint(3), [0, 1, 2]).eval_uint("1111"), 7) + self.assertEqual(AerVar(AerUint(5), [0, 1, 2]).eval_uint("111"), 7) + + # bool + self.assertEqual(AerVar(AerBool(), [0, 1, 2]).eval_bool("000"), False) + self.assertEqual(AerVar(AerBool(), [0, 1, 2]).eval_bool("001"), True) + + def test_unary_expression(self): + """test AerUnaryExpr""" + + # !(False) = True + self.assertEqual(AerUnaryExpr(AerUnaryOp.LogicNot, AerBoolValue(False)).eval_bool(""), True) + # !(True) = False + self.assertEqual(AerUnaryExpr(AerUnaryOp.LogicNot, AerBoolValue(True)).eval_bool(""), False) + # !(!(False)) = False + self.assertEqual( + AerUnaryExpr( + AerUnaryOp.LogicNot, AerUnaryExpr(AerUnaryOp.LogicNot, AerBoolValue(False)) + ).eval_bool(""), + False, + ) + # !(!(True)) = True + self.assertEqual( + AerUnaryExpr( + AerUnaryOp.LogicNot, AerUnaryExpr(AerUnaryOp.LogicNot, AerBoolValue(True)) + ).eval_bool(""), + True, + ) + + # !(0ul): Error + try: + AerUnaryExpr(AerUnaryOp.LogicNot, AerUintValue(3, 0)) + self.fail("do not reach here") + except Exception: + pass + + # !(1ul): Error + try: + AerUnaryExpr(AerUnaryOp.LogicNot, AerUintValue(3, 1)) + self.fail("do not reach here") + except Exception: + pass + + # ~(False): Error + try: + AerUnaryExpr(AerUnaryOp.BitNot, AerBoolValue(False)) + self.fail("do not reach here") + except Exception: + pass + + # ~(True): Error + try: + AerUnaryExpr(AerUnaryOp.BitNot, AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + + # ~(0b000) = 0b111 + self.assertEqual(AerUnaryExpr(AerUnaryOp.BitNot, AerUintValue(3, 0)).eval_uint(""), 0b111) + # ~(0b001) = 0b110 + self.assertEqual(AerUnaryExpr(AerUnaryOp.BitNot, AerUintValue(3, 1)).eval_uint(""), 0b110) + # ~(0b00000) = 0b11111 + self.assertEqual(AerUnaryExpr(AerUnaryOp.BitNot, AerUintValue(5, 0)).eval_uint(""), 0b11111) + # ~(0b00001) = 0b11110 + self.assertEqual(AerUnaryExpr(AerUnaryOp.BitNot, AerUintValue(5, 1)).eval_uint(""), 0b11110) + # ~(0b10101) = 0b01010 + self.assertEqual( + AerUnaryExpr(AerUnaryOp.BitNot, AerUintValue(5, 0b10101)).eval_uint(""), 0b01010 + ) + + def test_binary_expression(self): + """test AerBinaryExpr""" + + # (False && False) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicAnd, AerBoolValue(False), AerBoolValue(False)).eval_bool( + "" + ), + False, + ) + # (False && True) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicAnd, AerBoolValue(False), AerBoolValue(True)).eval_bool( + "" + ), + False, + ) + # (True && False) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicAnd, AerBoolValue(True), AerBoolValue(False)).eval_bool( + "" + ), + False, + ) + # (True && True) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicAnd, AerBoolValue(True), AerBoolValue(True)).eval_bool( + "" + ), + True, + ) + # (1 && 1): Error + try: + AerBinaryExpr(AerBinaryOp.LogicAnd, AerUintValue(3, 1), AerUintValue(3, 1)) + self.fail("do not reach here") + except Exception: + pass + + # (False || False) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicOr, AerBoolValue(False), AerBoolValue(False)).eval_bool( + "" + ), + False, + ) + # (False || True) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicOr, AerBoolValue(False), AerBoolValue(True)).eval_bool( + "" + ), + True, + ) + # (True || False) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicOr, AerBoolValue(True), AerBoolValue(False)).eval_bool( + "" + ), + True, + ) + # (True || True) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LogicOr, AerBoolValue(True), AerBoolValue(True)).eval_bool( + "" + ), + True, + ) + # (1 || 1): Error + try: + AerBinaryExpr(AerBinaryOp.LogicOr, AerUintValue(3, 1), AerUintValue(3, 1)) + self.fail("do not reach here") + except Exception: + pass + + # (False == False) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Equal, AerBoolValue(False), AerBoolValue(False)).eval_bool( + "" + ), + True, + ) + # (False == True) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Equal, AerBoolValue(False), AerBoolValue(True)).eval_bool(""), + False, + ) + # (1 == 1) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Equal, AerUintValue(3, 1), AerUintValue(3, 1)).eval_bool(""), + True, + ) + # (1 == 2) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Equal, AerUintValue(3, 1), AerUintValue(3, 2)).eval_bool(""), + False, + ) + + # (False != False) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.NotEqual, AerBoolValue(False), AerBoolValue(False)).eval_bool( + "" + ), + False, + ) + # (False != True) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.NotEqual, AerBoolValue(False), AerBoolValue(True)).eval_bool( + "" + ), + True, + ) + # (1 != 1) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.NotEqual, AerUintValue(3, 1), AerUintValue(3, 1)).eval_bool( + "" + ), + False, + ) + # (1 != 2) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.NotEqual, AerUintValue(3, 1), AerUintValue(3, 2)).eval_bool( + "" + ), + True, + ) + # (False < False): error + try: + AerBinaryExpr(AerBinaryOp.Less, AerBoolValue(False), AerBoolValue(False)) + self.fail("do not reach here") + except Exception: + pass + + # (False < True): error + try: + AerBinaryExpr(AerBinaryOp.Less, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (1 < 1) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Less, AerUintValue(3, 1), AerUintValue(3, 1)).eval_bool(""), + False, + ) + # (1 < 2) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Less, AerUintValue(3, 1), AerUintValue(3, 2)).eval_bool(""), + True, + ) + + # (False <= True): error + try: + AerBinaryExpr(AerBinaryOp.LessEqual, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (1 <= 1) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LessEqual, AerUintValue(3, 1), AerUintValue(3, 1)).eval_bool( + "" + ), + True, + ) + # (1 <= 2) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.LessEqual, AerUintValue(3, 1), AerUintValue(3, 2)).eval_bool( + "" + ), + True, + ) + + # (False > True): error + try: + AerBinaryExpr(AerBinaryOp.Greater, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (1 > 1) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Greater, AerUintValue(3, 1), AerUintValue(3, 1)).eval_bool( + "" + ), + False, + ) + + # (2 >= 1) = True + self.assertEqual( + AerBinaryExpr(AerBinaryOp.Greater, AerUintValue(3, 2), AerUintValue(3, 1)).eval_bool( + "" + ), + True, + ) + # (False >= True): error + try: + AerBinaryExpr(AerBinaryOp.GreaterEqual, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (1 >= 1) = True + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.GreaterEqual, AerUintValue(3, 1), AerUintValue(3, 1) + ).eval_bool(""), + True, + ) + # (2 >= 1) = True + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.GreaterEqual, AerUintValue(3, 2), AerUintValue(3, 1) + ).eval_bool(""), + True, + ) + + # (False & True): Uint -> error + try: + AerBinaryExpr(AerBinaryOp.BitAnd, AerBoolValue(False), AerBoolValue(True)).eval_uint("") + self.fail("do not reach here") + except Exception: + pass + # (False & True) = False + self.assertEqual( + AerBinaryExpr(AerBinaryOp.BitAnd, AerBoolValue(False), AerBoolValue(True)).eval_bool( + "" + ), + False, + ) + # (0b001 & 0b001) = 0b001 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitAnd, AerUintValue(3, 0b001), AerUintValue(3, 0b001) + ).eval_uint(""), + 0b001, + ) + # (0b001 & 0b010) = 0b000 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitAnd, AerUintValue(3, 0b001), AerUintValue(3, 0b010) + ).eval_uint(""), + 0b000, + ) + + # (False | True): error + try: + AerBinaryExpr(AerBinaryOp.BitOr, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (0b001 | 0b001) = 0b001 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(3, 0b001), AerUintValue(3, 0b001) + ).eval_uint(""), + 0b001, + ) + # (0b001 | 0b010) = 0b011 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(3, 0b001), AerUintValue(3, 0b010) + ).eval_uint(""), + 0b011, + ) + + # (False ^ True): error + try: + AerBinaryExpr(AerBinaryOp.BitOr, AerBoolValue(False), AerBoolValue(True)) + self.fail("do not reach here") + except Exception: + pass + # (0b001 ^ 0b001) = 0b000 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(3, 0b001), AerUintValue(3, 0b001) + ).eval_uint(""), + 0b001, + ) + # (0b001 ^ 0b010) = 0b011 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(3, 0b001), AerUintValue(3, 0b010) + ).eval_uint(""), + 0b011, + ) + + # overflow case + # (0b001 | 0b1010) = 0b1011 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(3, 0b001), AerUintValue(4, 0b1010) + ).eval_uint(""), + 0b1011, + ) + # (0b1010 | 0b001) = 0b1011 + self.assertEqual( + AerBinaryExpr( + AerBinaryOp.BitOr, AerUintValue(4, 0b1010), AerUintValue(3, 0b001) + ).eval_uint(""), + 0b1011, + ) diff --git a/test/terra/extensions/test_save_amplitudes.py b/test/terra/extensions/test_save_amplitudes.py index 21dcc0043d..c3ba575252 100644 --- a/test/terra/extensions/test_save_amplitudes.py +++ b/test/terra/extensions/test_save_amplitudes.py @@ -13,7 +13,6 @@ import unittest -from qiskit.extensions.exceptions import ExtensionError from qiskit_aer.library import SaveAmplitudes from ..common import QiskitAerTestCase @@ -23,11 +22,11 @@ class TestSaveAmplitudes(QiskitAerTestCase): def test_invalid_key_raises(self): """Test save instruction key is str""" - self.assertRaises(ExtensionError, lambda: SaveAmplitudes(1, [0], 1)) + self.assertRaises(TypeError, lambda: SaveAmplitudes(1, [0], 1)) def test_invalid_state_raises(self): """Test non-Hermitian op raises exception.""" - self.assertRaises(ExtensionError, lambda: SaveAmplitudes(2, [4], "key")) + self.assertRaises(ValueError, lambda: SaveAmplitudes(2, [4], "key")) def test_default_kwarg(self): """Test default kwargs""" diff --git a/test/terra/extensions/test_save_expval.py b/test/terra/extensions/test_save_expval.py index 76ab55f899..1549f95c87 100644 --- a/test/terra/extensions/test_save_expval.py +++ b/test/terra/extensions/test_save_expval.py @@ -13,7 +13,6 @@ import unittest -from qiskit.extensions.exceptions import ExtensionError from qiskit_aer.library import SaveExpectationValue, SaveExpectationValueVariance from qiskit.quantum_info.operators import Pauli @@ -25,12 +24,12 @@ class TestSaveExpectationValue(QiskitAerTestCase): def test_invalid_key_raises(self): """Test save instruction key is str""" - self.assertRaises(ExtensionError, lambda: SaveExpectationValue(Pauli("Z"), 1)) + self.assertRaises(TypeError, lambda: SaveExpectationValue(Pauli("Z"), 1)) def test_nonhermitian_raises(self): """Test non-Hermitian op raises exception.""" op = [[0, 1j], [1j, 0]] - self.assertRaises(ExtensionError, lambda: SaveExpectationValue(op, "expval")) + self.assertRaises(ValueError, lambda: SaveExpectationValue(op, "expval")) def test_default_kwarg(self): """Test default kwargs""" @@ -86,12 +85,12 @@ class TestSaveExpectationValueVariance(QiskitAerTestCase): def test_invalid_key_raises(self): """Test save instruction key is str""" - self.assertRaises(ExtensionError, lambda: SaveExpectationValueVariance(Pauli("Z"), 1)) + self.assertRaises(TypeError, lambda: SaveExpectationValueVariance(Pauli("Z"), 1)) def test_nonhermitian_raises(self): """Test non-Hermitian op raises exception.""" op = [[0, 1j], [1j, 0]] - self.assertRaises(ExtensionError, lambda: SaveExpectationValueVariance(op, "expval")) + self.assertRaises(ValueError, lambda: SaveExpectationValueVariance(op, "expval")) def test_default_kwarg(self): """Test default kwargs""" diff --git a/test/terra/noise/test_noise_model.py b/test/terra/noise/test_noise_model.py index a84c080567..d851288459 100644 --- a/test/terra/noise/test_noise_model.py +++ b/test/terra/noise/test_noise_model.py @@ -388,7 +388,7 @@ def test_can_run_circuits_with_delay_noise(self): circ.cx(0, 1) circ.measure_all() - backend = FakeLagos() + backend = FakeLagosV2() noise_model = NoiseModel.from_backend(backend) qc = transpile(circ, backend, scheduling_method="alap") diff --git a/test/terra/noise/test_noise_transformation.py b/test/terra/noise/test_noise_transformation.py index 656db8f718..2ab7e3461b 100644 --- a/test/terra/noise/test_noise_transformation.py +++ b/test/terra/noise/test_noise_transformation.py @@ -19,9 +19,8 @@ import numpy from qiskit.circuit import Reset -from qiskit.circuit.library.standard_gates import IGate -from qiskit.circuit.library.standard_gates import XGate, YGate, ZGate, HGate, SGate -from qiskit.extensions import UnitaryGate +from qiskit.circuit.library.standard_gates import IGate, XGate, YGate, ZGate, HGate, SGate +from qiskit.circuit.library.generalized_gates import UnitaryGate from qiskit.quantum_info.operators.channel import Kraus from qiskit.quantum_info.random import random_unitary from qiskit_aer.noise import NoiseModel diff --git a/test/terra/noise/test_quantum_error.py b/test/terra/noise/test_quantum_error.py index 07b790fe32..e8abc23639 100644 --- a/test/terra/noise/test_quantum_error.py +++ b/test/terra/noise/test_quantum_error.py @@ -20,7 +20,7 @@ from qiskit.circuit import QuantumCircuit, Reset, Measure from qiskit.circuit.library.standard_gates import IGate, XGate, YGate, ZGate -from qiskit.extensions import UnitaryGate +from qiskit.circuit.library.generalized_gates import UnitaryGate from qiskit.quantum_info.operators import SuperOp, Kraus, Pauli from qiskit_aer.noise import QuantumError, pauli_error, reset_error from qiskit_aer.noise.noiseerror import NoiseError diff --git a/test/terra/primitives/test_estimator.py b/test/terra/primitives/test_estimator.py index 96c13cf59b..dfd658e05c 100644 --- a/test/terra/primitives/test_estimator.py +++ b/test/terra/primitives/test_estimator.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2022. +# (C) Copyright IBM 2022, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -23,7 +23,6 @@ from qiskit.circuit import Parameter, QuantumCircuit from qiskit.circuit.library import RealAmplitudes from qiskit.exceptions import QiskitError -from qiskit.opflow import PauliSumOp from qiskit.primitives import EstimatorResult from qiskit.quantum_info import Operator, SparsePauliOp @@ -53,25 +52,13 @@ def setUp(self): def test_estimator(self, abelian_grouping): """test for a simple use case""" lst = [("XX", 1), ("YY", 2), ("ZZ", 3)] - with self.assertWarns(DeprecationWarning): - with self.subTest("PauliSumOp"): - observable = PauliSumOp.from_list(lst) - ansatz = RealAmplitudes(num_qubits=2, reps=2) - est = Estimator( - backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping - ) - result = est.run( - ansatz, observable, parameter_values=[[0, 1, 1, 2, 3, 5]], seed=15 - ).result() - self.assertIsInstance(result, EstimatorResult) - np.testing.assert_allclose(result.values, [1.728515625]) - with self.subTest("SparsePauliOp"): observable = SparsePauliOp.from_list(lst) ansatz = RealAmplitudes(num_qubits=2, reps=2) - est = Estimator( - backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping - ) + with self.assertWarns(DeprecationWarning): + est = Estimator( + backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping + ) result = est.run( ansatz, observable, parameter_values=[[0, 1, 1, 2, 3, 5]], seed=15 ).result() @@ -88,9 +75,10 @@ def test_estimator(self, abelian_grouping): ] ) ansatz = RealAmplitudes(num_qubits=2, reps=2) - est = Estimator( - backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping - ) + with self.assertWarns(DeprecationWarning): + est = Estimator( + backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping + ) result = est.run(ansatz, observable, parameter_values=[[0] * 6], seed=15).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [-0.4], rtol=0.02) @@ -98,7 +86,7 @@ def test_estimator(self, abelian_grouping): @data(True, False) def test_init_observable_from_operator(self, abelian_grouping): """test for evaluate without parameters""" - circuit = self.ansatz.bind_parameters([0, 1, 1, 2, 3, 5]) + circuit = self.ansatz.assign_parameters([0, 1, 1, 2, 3, 5]) matrix = Operator( [ [-1.06365335, 0.0, 0.0, 0.1809312], @@ -107,7 +95,8 @@ def test_init_observable_from_operator(self, abelian_grouping): [0.1809312, 0.0, 0.0, -1.06365335], ] ) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run([circuit], [matrix], seed=15, shots=8192).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [self.expval], rtol=0.02) @@ -115,7 +104,8 @@ def test_init_observable_from_operator(self, abelian_grouping): @data(True, False) def test_evaluate(self, abelian_grouping): """test for evaluate""" - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run( self.ansatz, self.observable, parameter_values=[[0, 1, 1, 2, 3, 5]], seed=15, shots=8192 ).result() @@ -125,7 +115,8 @@ def test_evaluate(self, abelian_grouping): @data(True, False) def test_evaluate_multi_params(self, abelian_grouping): """test for evaluate with multiple parameters""" - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run( [self.ansatz] * 2, [self.observable] * 2, @@ -138,8 +129,9 @@ def test_evaluate_multi_params(self, abelian_grouping): @data(True, False) def test_evaluate_no_params(self, abelian_grouping): """test for evaluate without parameters""" - circuit = self.ansatz.bind_parameters([0, 1, 1, 2, 3, 5]) - est = Estimator(abelian_grouping=abelian_grouping) + circuit = self.ansatz.assign_parameters([0, 1, 1, 2, 3, 5]) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run(circuit, self.observable, seed=15, shots=8192).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [self.expval], rtol=0.02) @@ -151,7 +143,9 @@ def test_run_with_multiple_observables_and_none_parameters(self, abelian_groupin circuit.h(0) circuit.cx(0, 1) circuit.cx(1, 2) - est = Estimator(abelian_grouping=abelian_grouping) + # Skip transpilation until solve qiskit-terra issue(10568) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping, skip_transpilation=True) result = est.run( [circuit] * 2, [SparsePauliOp("ZZZ"), SparsePauliOp("III")], seed=15 ).result() @@ -168,7 +162,8 @@ def test_1qubit(self, abelian_grouping): op0 = SparsePauliOp.from_list([("I", 1)]) op1 = SparsePauliOp.from_list([("Z", 1)]) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) with self.subTest("test circuit 0, observable 0"): result = est.run(qc0, op0).result() self.assertIsInstance(result, EstimatorResult) @@ -200,7 +195,8 @@ def test_2qubits(self, abelian_grouping): op1 = SparsePauliOp.from_list([("ZI", 1)]) op2 = SparsePauliOp.from_list([("IZ", 1)]) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) with self.subTest("test circuit 0, observable 0"): result = est.run(qc0, op0).result() self.assertIsInstance(result, EstimatorResult) @@ -237,7 +233,8 @@ def test_empty_parameter(self, abelian_grouping): n = 2 qc = QuantumCircuit(n) op = SparsePauliOp.from_list([("I" * n, 1)]) - estimator = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + estimator = Estimator(abelian_grouping=abelian_grouping) with self.subTest("one circuit"): result = estimator.run(qc, op, shots=1000).result() np.testing.assert_allclose(result.values, [1]) @@ -257,7 +254,8 @@ def test_numpy_params(self, abelian_grouping): params_array = np.random.rand(k, qc.num_parameters) params_list = params_array.tolist() params_list_array = list(params_array) - estimator = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + estimator = Estimator(abelian_grouping=abelian_grouping) target = estimator.run([qc] * k, [op] * k, params_list, seed=15).result() with self.subTest("ndarrary"): @@ -285,7 +283,8 @@ def test_with_shots_option_with_approximation(self, abelian_grouping): def test_with_shots_option_without_approximation(self): """test with shots option.""" - est = Estimator(approximation=False, abelian_grouping=False) + with self.assertWarns(DeprecationWarning): + est = Estimator(approximation=False, abelian_grouping=False) result = est.run( self.ansatz, self.observable, parameter_values=[[0, 1, 1, 2, 3, 5]], shots=1024, seed=15 ).result() @@ -295,15 +294,15 @@ def test_with_shots_option_without_approximation(self): def test_warn_shots_none_without_approximation(self): """Test waning for shots=None without approximation.""" - est = Estimator(approximation=False) - with self.assertWarns(RuntimeWarning): - result = est.run( - self.ansatz, - self.observable, - parameter_values=[[0, 1, 1, 2, 3, 5]], - shots=None, - seed=15, - ).result() + with self.assertWarns(DeprecationWarning): + est = Estimator(approximation=False) + result = est.run( + self.ansatz, + self.observable, + parameter_values=[[0, 1, 1, 2, 3, 5]], + shots=None, + seed=15, + ).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [-1.313831587508902]) self.assertIsInstance(result.metadata[0]["variance"], float) diff --git a/test/terra/primitives/test_sampler.py b/test/terra/primitives/test_sampler.py index 4cd6ba3b7f..0bb0bb1bb6 100644 --- a/test/terra/primitives/test_sampler.py +++ b/test/terra/primitives/test_sampler.py @@ -252,7 +252,7 @@ def test_num_clbits(self, shots): qc.h(0) qc.measure_all() - result = Sampler().run(qc, shots=shots, seed=15).result() + result = Sampler().run(qc, shots=shots, seed=20).result() quasis = result.quasi_dists[0] bin_probs = quasis.binary_probabilities() self.assertDictAlmostEqual(bin_probs, {"0000": 0.5, "0001": 0.5}, delta=1e-2) diff --git a/test/terra/reference/ref_conditionals.py b/test/terra/reference/ref_conditionals.py index d048479c5b..3666cc34a6 100644 --- a/test/terra/reference/ref_conditionals.py +++ b/test/terra/reference/ref_conditionals.py @@ -14,6 +14,7 @@ Test circuits and reference outputs for conditional gates. """ +import math import numpy as np from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.circuit import Instruction @@ -44,6 +45,9 @@ def add_conditional_x(circuit, qreg, creg, val, conditional_type): circuit.append(x_kraus, [qreg]).c_if(creg, val) elif conditional_type == "superop": circuit.append(x_superop, [qreg]).c_if(creg, val) + elif conditional_type == "reset": + circuit.x(qreg).c_if(creg, val) + circuit.reset(qreg).c_if(creg, val) else: circuit.x(qreg).c_if(creg, val) @@ -133,6 +137,30 @@ def conditional_counts_1bit(shots, hex_counts=True): return targets +def conditional_counts_1bit_with_reset(shots, hex_counts=True): + """Conditional circuits reference counts.""" + targets = [] + if hex_counts: + # Conditional on 0 (cond = 0), "0 1" -> "0 0" + targets.append({"0x0": shots}) + # Conditional on 0 (cond = 1), result "1 0" -> "1 0" + targets.append({"0x2": shots}) + # Conditional on 1 (cond = 0), # result "0 0" -> "0 0" + targets.append({"0x0": shots}) + # Conditional on 1 (cond = 1), # result "1 1" -> "1 0" + targets.append({"0x2": shots}) + else: + # Conditional on 0 (cond = 0), "0 1" -> "0 0" + targets.append({"0 0": shots}) + # Conditional on 0 (cond = 1), result "1 0" -> "1 0" + targets.append({"1 0": shots}) + # Conditional on 1 (cond = 0), # result "0 0" -> "0 0" + targets.append({"0 0": shots}) + # Conditional on 1 (cond = 1), # result "1 1" -> "1 0" + targets.append({"1 0": shots}) + return targets + + def conditional_statevector_1bit(): """Conditional circuits reference statevector.""" targets = [] diff --git a/tools/deploy_documentation.sh b/tools/deploy_documentation.sh deleted file mode 100755 index 201e275c8f..0000000000 --- a/tools/deploy_documentation.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# Script for pushing the documentation to qiskit.org/ecosystem. -set -e - -curl https://downloads.rclone.org/rclone-current-linux-amd64.deb -o rclone.deb -sudo apt-get install -y ./rclone.deb - -RCLONE_CONFIG_PATH=$(rclone config file | tail -1) - -# Build the documentation. -tox -edocs - -echo "show current dir: " -pwd - -# Push to qiskit.org/ecosystem -openssl aes-256-cbc -K $encrypted_rclone_key -iv $encrypted_rclone_iv -in tools/rclone.conf.enc -out $RCLONE_CONFIG_PATH -d -echo "Pushing built docs to website" -rclone sync --progress ./docs/_build/html IBMCOS:qiskit-org-web-resources/ecosystem/aer diff --git a/tools/rclone.conf.enc b/tools/rclone.conf.enc deleted file mode 100644 index 985bd728ab..0000000000 Binary files a/tools/rclone.conf.enc and /dev/null differ diff --git a/tox.ini b/tox.ini index 5b5a17c4ef..7a8d31afd3 100644 --- a/tox.ini +++ b/tox.ini @@ -53,7 +53,7 @@ deps = build qiskit-ibmq-provider commands = - python -I -m build --wheel -C=--build-option=-- -C=--build-option=-- -C=--build-option=-j4 + python -I -m build --wheel -C=--build-option=-j4 pip install --find-links={toxinidir}/dist qiskit_aer sphinx-build -W -b html docs/ docs/_build/html -j auto {posargs}