From b77f00578101d449ae9489a4ab164a7d11dcd1b3 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 31 May 2024 10:15:53 +0900 Subject: [PATCH] Release 0.14.2 (#2145) * release 0.14.2 * Disable test shot_branching on MacOS (#2143) * remove test_shot_branching * disable sho_branching tests on MacOS * fix test * fix test * format * fix test_shot_branching * fix test_runtime_parameterization * fix tests for the latest Qiskit (#2138) * Remove qiskit aer translation stage (#2142) This commit removes the qiskit aer translation plugin. This was added as a workaround for a Qiskit/qiskit#11351. This has been fixed in Qiskit since 0.45.2 and is no longer necessary. The mechanism by which the workaround worked was unsound in practice as it was mutating the target and also explicitly using private attributes of the Target. This is causing real issues now as it only worked by assuming the target wasn't shared between passmanagers which is never guaranteed. Similarly the reliance on internal private attributes of the Target class will cause issues in the future when the target internals change (see Qiskit/qiskit#12292). This commit opts to remove the plugin in its entirity as it's no longer necessary and actively causing issues with Qiskit 1.1 and transpiling targeting aer backends with >1 circuit. As it's private internal detail there isn't a release note. Fixes Qiskit/qiskit#12425 Fixes #2141 * Fix issue 2084 again (#2119) * Fix issue 2084 again * format * fix test * fix test * Always hook omp functions in Mac (#2128) * always hook omp functions in Mac * fix recent test failures with the latest qiskit --------- Co-authored-by: Jun Doi * Add simulator_metadata in metadata of SamplerV2 (#2109) Co-authored-by: Hiroshi Horii * Fix cuStateVec_enable option (#2146) * Fix cuStateVec_enable option * fix function name * Add support for rotation gates (#2147) * add rotation gates * add cr* gates to operations.hpp * fix test for stabilkize/extended-stabilizer * fix test again * Fix deterministic measure of stabilizer (#2132) * Fix deterministic measure of stabilizer * fix accumulation in loop * format --------- Co-authored-by: Hiroshi Horii * Fix init of EstimatorV2 and SamplerV2 (#2120) * fix init of EstimatorV2 and SamplerV2 to handle method * add release note * fix from_backend and example in README * remove setting density_matrix * Fix deploy.yml (#2110) Co-authored-by: Hiroshi Horii Co-authored-by: Luciano Bello * Add support for ECR gate to MPS (#2137) * Add support for ECR gate * replace is not to != * fix release note * Fix ecr implementation for stabilizer/extended-stabilizer * Handle gates with ctrl_stete=0 (#2148) * handle cx gate with ctrl_stete=0 * add handling *_o0, add test for cx_o0 * format * fix test * fix test * fix test cx * fix to handle multiple control states * fix ctrl_state * format * resolve conflict again * fix aer_compiler * fix random seed (#2151) Co-authored-by: Hiroshi Horii * Move delay gate to custom instructions (#2153) --------- Co-authored-by: Matthew Treinish Co-authored-by: Hiroshi Horii Co-authored-by: Luciano Bello Co-authored-by: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com> --- .github/workflows/deploy.yml | 15 +- README.md | 8 +- docs/conf.py | 4 +- qiskit_aer/VERSION.txt | 2 +- qiskit_aer/backends/aer_compiler.py | 37 +++- qiskit_aer/backends/aer_simulator.py | 30 ++- qiskit_aer/backends/aerbackend.py | 9 +- qiskit_aer/backends/backend_utils.py | 27 ++- qiskit_aer/backends/plugin/__init__.py | 0 .../backends/plugin/aer_backend_plugin.py | 126 ------------ .../wrappers/aer_controller_binding.hpp | 2 + qiskit_aer/primitives/estimator_v2.py | 14 +- qiskit_aer/primitives/sampler_v2.py | 13 +- ..._custom_instructions-e1bf80ec3598bfd1.yaml | 6 + .../add_ecr_to_mps-0eec56596fc486c7.yaml | 7 + ...add_rotation_support-c0ef8155a761e560.yaml | 8 + ...2_simulator_metadata-e17850d483439f9a.yaml | 5 + ..._enabling_cuStateVec-1a2f1d3e35f3129d.yaml | 6 + .../notes/fix_issue2084-632a829da1a8dfc5.yaml | 7 + ...fix_primitiveV2_init-afe7b331ddbef538.yaml | 5 + ...x_stabilizer_measure-a06d761eba2546d2.yaml | 5 + .../init_omp_first-c9d19dbfa1a0fc2b.yaml | 6 + setup.py | 7 +- src/controllers/controller_execute.hpp | 18 +- src/framework/operations.hpp | 44 +++-- .../density_matrix/densitymatrix_state.hpp | 3 + .../extended_stabilizer_state.hpp | 50 ++++- src/simulators/extended_stabilizer/gates.hpp | 6 +- .../matrix_product_state.hpp | 12 +- .../matrix_product_state_internal.hpp | 3 +- src/simulators/parallel_state_executor.hpp | 4 + src/simulators/stabilizer/clifford.hpp | 186 +++++++----------- .../stabilizer/stabilizer_state.hpp | 53 +---- .../chunk/cuStateVec_chunk_container.hpp | 1 - .../statevector/statevector_state.hpp | 25 ++- .../tensor_network/tensor_net_state.hpp | 7 +- src/simulators/unitary/unitary_state.hpp | 24 ++- .../backends/aer_simulator/test_chunk.py | 5 +- .../backends/aer_simulator/test_cliffords.py | 9 +- .../aer_simulator/test_control_flow.py | 8 +- .../backends/aer_simulator/test_measure.py | 32 +++ .../backends/aer_simulator/test_rotation.py | 11 +- .../aer_simulator/test_shot_branching.py | 4 +- .../terra/backends/test_parameterized_qobj.py | 10 +- .../backends/test_runtime_parameterization.py | 4 + test/terra/primitives/test_sampler.py | 10 + test/terra/primitives/test_sampler_v2.py | 10 +- test/terra/reference/ref_2q_clifford.py | 26 +++ test/terra/states/test_aer_densitymatrix.py | 9 +- test/terra/states/test_aer_statevector.py | 10 +- 50 files changed, 499 insertions(+), 434 deletions(-) delete mode 100644 qiskit_aer/backends/plugin/__init__.py delete mode 100644 qiskit_aer/backends/plugin/aer_backend_plugin.py create mode 100644 releasenotes/notes/add_delay_custom_instructions-e1bf80ec3598bfd1.yaml create mode 100644 releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml create mode 100644 releasenotes/notes/add_rotation_support-c0ef8155a761e560.yaml create mode 100644 releasenotes/notes/add_sampler_v2_simulator_metadata-e17850d483439f9a.yaml create mode 100644 releasenotes/notes/fix_enabling_cuStateVec-1a2f1d3e35f3129d.yaml create mode 100644 releasenotes/notes/fix_issue2084-632a829da1a8dfc5.yaml create mode 100644 releasenotes/notes/fix_primitiveV2_init-afe7b331ddbef538.yaml create mode 100644 releasenotes/notes/fix_stabilizer_measure-a06d761eba2546d2.yaml create mode 100644 releasenotes/notes/init_omp_first-c9d19dbfa1a0fc2b.yaml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 36d214ab24..148250251e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,7 +23,6 @@ jobs: - name: Build wheels env: AER_CMAKE_OPENMP_BUILD: 1 - CIBW_SKIP: "pp* cp38-macosx_arm64 cp39-macosx_arm64" run: python -m cibuildwheel --output-dir wheelhouse - uses: actions/upload-artifact@v3 with: @@ -133,7 +132,7 @@ jobs: - name: Maximize build space uses: easimon/maximize-build-space@master with: - root-reserve-mb: 30000 + root-reserve-mb: 32000 swap-size-mb: 1024 remove-dotnet: 'true' remove-android: 'true' @@ -149,9 +148,10 @@ jobs: 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 cache purge && pip install nvidia-cuda-runtime-cu11 nvidia-cublas-cu11 nvidia-cusolver-cu11 nvidia-cusparse-cu11 cuquantum-cu11" + CIBW_BEFORE_ALL: "pip cache purge && 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* cp37* *musllinux*" + CIBW_TEST_SKIP: "*" 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: | @@ -176,7 +176,7 @@ jobs: - name: Maximize build space uses: easimon/maximize-build-space@master with: - root-reserve-mb: 30000 + root-reserve-mb: 32000 swap-size-mb: 1024 remove-dotnet: 'true' remove-android: 'true' @@ -192,9 +192,10 @@ jobs: 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.4.0/local_installers/cuda-repo-rhel7-12-4-local-12.4.0_550.54.14-1.x86_64.rpm && rpm -i cuda-repo-rhel7-12-4-local-12.4.0_550.54.14-1.x86_64.rpm && yum clean all && yum -y install nvidia-driver-latest-dkms && yum -y install cuda-toolkit-12-4 && yum -y install openblas-devel && yum clean all" - CIBW_BEFORE_BUILD : "pip cache purge && pip install nvidia-cuda-runtime-cu12 nvidia-nvjitlink-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 cuquantum-cu12" + CIBW_BEFORE_ALL: "pip cache purge && yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda-repo-rhel7-12-4-local-12.4.0_550.54.14-1.x86_64.rpm && rpm -i cuda-repo-rhel7-12-4-local-12.4.0_550.54.14-1.x86_64.rpm && yum clean all && yum -y install nvidia-driver-latest-dkms && yum -y install cuda-toolkit-12-4 && yum -y install openblas-devel && 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* *musllinux*" + CIBW_TEST_SKIP: "*" 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: | diff --git a/README.md b/README.md index cfd4cd36f7..770a172177 100755 --- a/README.md +++ b/README.md @@ -134,13 +134,13 @@ provider = QiskitRuntimeService(channel='ibm_quantum', token="set your own token backend = provider.get_backend("ibm_kyoto") # create sampler from the actual backend -sampler.from_backend(backend) +sampler = SamplerV2.from_backend(backend) # run a sampler job on the parameterized circuits with noise model of the actual hardware -job3 = sampler.run([(pqc, theta1), (pqc2, theta2)]) +bell_t = transpile(bell, AerSimulator(basis_gates=["ecr", "id", "rz", "sx"]), optimization_level=0) +job3 = sampler.run([bell_t], shots=128) job_result = job3.result() -print(f"Parameterized for Bell circuit w/noise: {job_result[0].data.meas.get_counts()}") - +print(f"counts for Bell circuit w/noise: {job_result[0].data.meas.get_counts()}") ``` ## Contribution Guidelines diff --git a/docs/conf.py b/docs/conf.py index b0bf2c26d5..08bf27f4da 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -47,9 +47,9 @@ author = 'Qiskit Development Team' # The short X.Y version -version = '0.14.1' +version = '0.14.2' # The full version, including alpha/beta/rc tags -release = '0.14.1' +release = '0.14.2' templates_path = ['_templates'] diff --git a/qiskit_aer/VERSION.txt b/qiskit_aer/VERSION.txt index 930e3000bd..e867cc2a66 100644 --- a/qiskit_aer/VERSION.txt +++ b/qiskit_aer/VERSION.txt @@ -1 +1 @@ -0.14.1 +0.14.2 diff --git a/qiskit_aer/backends/aer_compiler.py b/qiskit_aer/backends/aer_compiler.py index 12758b4573..43bff9123c 100644 --- a/qiskit_aer/backends/aer_compiler.py +++ b/qiskit_aer/backends/aer_compiler.py @@ -812,17 +812,43 @@ def _assemble_op( aer_cond_expr = conditional_expr.accept(_AssembleExprImpl(circ)) if conditional_expr else None + # check if there is ctrl_state option + ctrl_state_pos = name.find("_o") + if ctrl_state_pos > 0: + gate_name = name[0:ctrl_state_pos] + else: + gate_name = name + num_of_aer_ops = 1 # fmt: off - if basis_gates is None and name in { + if (gate_name in { "ccx", "ccz", "cp", "cswap", "csx", "cx", "cy", "cz", "delay", "ecr", "h", "id", "mcp", "mcphase", "mcr", "mcrx", "mcry", "mcrz", "mcswap", "mcsx", "mcu", "mcu1", "mcu2", "mcu3", "mcx", "mcx_gray", "mcy", "mcz", "p", "r", "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, aer_cond_expr, - label if label else name) + "crx", "cry", "crz", + }) and (basis_gates is None or gate_name in basis_gates): + if ctrl_state_pos > 0: + # Add x gates for ctrl qubits which state=0 + ctrl_state = int(name[ctrl_state_pos+2:len(name)]) + for i in range(len(qubits)): + if (ctrl_state >> i) & 1 == 0: + qubits_i = [qubits[len(qubits) - 1 - i]] + aer_circ.gate("x", qubits_i, params, [], conditional_reg, aer_cond_expr, + label if label else "x") + num_of_aer_ops += 1 + aer_circ.gate(gate_name, qubits, params, [], conditional_reg, aer_cond_expr, + label if label else gate_name) + for i in range(len(qubits)): + if (ctrl_state >> i) & 1 == 0: + qubits_i = [qubits[len(qubits) - 1 - i]] + aer_circ.gate("x", qubits_i, params, [], conditional_reg, aer_cond_expr, + label if label else "x") + num_of_aer_ops += 1 + else: + 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) @@ -914,9 +940,6 @@ def _assemble_op( aer_circ.mark(qubits, params) elif name == "qerror_loc": aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg, aer_cond_expr) - elif basis_gates is not None and name in basis_gates: - aer_circ.gate(name, qubits, params, [], conditional_reg, aer_cond_expr, - label if label else name) 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 958a10ba89..e1676ce61a 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -304,6 +304,7 @@ class AerSimulator(AerBackend): than number of total shots. This option is available for ``"statevector"``, ``"density_matrix"`` and ``"tensor_network"``. + WARNING: `shot_branching` option is unstable on MacOS currently * ``shot_branching_sampling_enable`` (bool): This option enables/disables applying sampling measure if the input circuit has all the measure @@ -524,6 +525,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "delay", ] ), "density_matrix": sorted( @@ -548,6 +550,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "delay", ] ), "matrix_product_state": sorted( @@ -574,6 +577,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "delay", ] ), "stabilizer": sorted( @@ -597,6 +601,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "delay", ] ), "extended_stabilizer": sorted( @@ -606,6 +611,7 @@ class AerSimulator(AerBackend): "roerror", "save_statevector", "reset", + "delay", ] ), "unitary": sorted( @@ -614,6 +620,7 @@ class AerSimulator(AerBackend): "save_unitary", "set_unitary", "reset", + "delay", ] ), "superop": sorted( @@ -626,6 +633,7 @@ class AerSimulator(AerBackend): "save_superop", "set_superop", "reset", + "delay", ] ), "tensor_network": sorted( @@ -649,6 +657,7 @@ class AerSimulator(AerBackend): "set_density_matrix", "reset", "switch_case", + "delay", ] ), } @@ -744,6 +753,9 @@ def __init__( backend_options=backend_options, ) + if "basis_gates" in backend_options.items(): + self._check_basis_gates(backend_options["basis_gates"]) + @classmethod def _default_options(cls): return Options( @@ -897,11 +909,12 @@ def configuration(self): config = copy.copy(self._configuration) for key, val in self._options_configuration.items(): setattr(config, key, val) + + method = getattr(self.options, "method", "automatic") + # Update basis gates based on custom options, config, method, # and noise model - config.custom_instructions = self._CUSTOM_INSTR[ - getattr(self.options, "method", "automatic") - ] + config.custom_instructions = self._CUSTOM_INSTR[method] config.basis_gates = self._cached_basis_gates + config.custom_instructions return config @@ -932,6 +945,9 @@ def set_option(self, key, value): f" are: {self.available_methods()}" ) self._set_method_config(value) + if key == "basis_gates": + self._check_basis_gates(value) + super().set_option(key, value) if key in ["method", "noise_model", "basis_gates"]: self._cached_basis_gates = self._basis_gates() @@ -1046,3 +1062,11 @@ def _set_method_config(self, method=None): self._set_configuration_option("description", description) self._set_configuration_option("n_qubits", n_qubits) + + def _check_basis_gates(self, basis_gates): + method = getattr(self.options, "method", "automatic") + # check if basis_gates contains non-supported gates + if method != "automatic": + for gate in basis_gates: + if gate not in self._BASIS_GATES[method]: + raise AerError(f"Invalid gate {gate} for simulation method {method}.") diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index ed8059a57b..fd0772964e 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -352,7 +352,7 @@ def target(self): def set_max_qubits(self, max_qubits): """Set maximun number of qubits to be used for this backend.""" - if self._target is not None: + if self._target is None: self._configuration.n_qubits = max_qubits def clear_options(self): @@ -737,10 +737,3 @@ def __repr__(self): name = self.__class__.__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 09a199380b..a030578b6c 100644 --- a/qiskit_aer/backends/backend_utils.py +++ b/qiskit_aer/backends/backend_utils.py @@ -25,6 +25,9 @@ from .compatibility import Statevector, DensityMatrix, StabilizerState, Operator, SuperOp +# pylint: disable=import-error, no-name-in-module, abstract-method +from .controller_wrappers import aer_initialize_libraries + # Available system memory SYSTEM_MEMORY_GB = psutil.virtual_memory().total / (1024**3) @@ -35,6 +38,7 @@ # Location where we put external libraries that will be # loaded at runtime by the simulator extension LIBRARY_DIR = os.path.dirname(__file__) +aer_initialize_libraries(LIBRARY_DIR) LEGACY_METHOD_MAP = { "statevector_cpu": ("statevector", "CPU"), @@ -87,6 +91,9 @@ "rzx", "ccx", "ccz", + "crx", + "cry", + "crz", "cswap", "mcx", "mcy", @@ -107,7 +114,6 @@ "diagonal", "multiplexer", "initialize", - "delay", "pauli", "mcx_gray", "ecr", @@ -148,7 +154,6 @@ "ccx", "unitary", "diagonal", - "delay", "pauli", "ecr", ] @@ -179,7 +184,6 @@ "ccx", "unitary", "roerror", - "delay", "pauli", "r", "rx", @@ -193,6 +197,7 @@ "cswap", "diagonal", "initialize", + "ecr", ] ), "stabilizer": sorted( @@ -210,11 +215,8 @@ "cy", "cz", "swap", - "delay", "pauli", "ecr", - "rx", - "ry", "rz", ] ), @@ -239,8 +241,9 @@ "p", "ccx", "ccz", - "delay", "pauli", + "ecr", + "rz", ] ), "unitary": sorted( @@ -282,6 +285,9 @@ "ccx", "ccz", "cswap", + "crx", + "cry", + "crz", "mcx", "mcy", "mcz", @@ -300,7 +306,6 @@ "unitary", "diagonal", "multiplexer", - "delay", "pauli", "ecr", ] @@ -340,7 +345,6 @@ "ccx", "unitary", "diagonal", - "delay", "pauli", ] ), @@ -383,6 +387,9 @@ "ccx", "ccz", "cswap", + "crx", + "cry", + "crz", "mcx", "mcy", "mcz", @@ -402,9 +409,9 @@ "diagonal", "multiplexer", "initialize", - "delay", "pauli", "mcx_gray", + "ecr", ] ), } diff --git a/qiskit_aer/backends/plugin/__init__.py b/qiskit_aer/backends/plugin/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py deleted file mode 100644 index 73be26fcef..0000000000 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ /dev/null @@ -1,126 +0,0 @@ -# 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/wrappers/aer_controller_binding.hpp b/qiskit_aer/backends/wrappers/aer_controller_binding.hpp index c530cfc8f0..997d38adf7 100644 --- a/qiskit_aer/backends/wrappers/aer_controller_binding.hpp +++ b/qiskit_aer/backends/wrappers/aer_controller_binding.hpp @@ -86,6 +86,8 @@ void read_value(const py::tuple &t, size_t index, T &v) { template void bind_aer_controller(MODULE m) { + m.def("aer_initialize_libraries", &initialize_libraries); + py::class_> aer_ctrl(m, "aer_controller_execute"); aer_ctrl.def(py::init<>()); diff --git a/qiskit_aer/primitives/estimator_v2.py b/qiskit_aer/primitives/estimator_v2.py index a4bdb4da68..bfeeca73c5 100644 --- a/qiskit_aer/primitives/estimator_v2.py +++ b/qiskit_aer/primitives/estimator_v2.py @@ -70,12 +70,14 @@ def __init__( the runtime options (``run_options``). """ self._options = Options(**options) if options else Options() - method = "density_matrix" if "noise_model" in self.options.backend_options else "automatic" - self._backend = AerSimulator(method=method, **self.options.backend_options) - - def from_backend(self, backend, **options): - """use external backend""" - self._backend.from_backend(backend, **options) + self._backend = AerSimulator(**self.options.backend_options) + + @classmethod + def from_backend(cls, backend, **options): + """make new sampler that uses external backend""" + estimator = cls(**options) + estimator._backend = AerSimulator.from_backend(backend) + return estimator @property def options(self) -> Options: diff --git a/qiskit_aer/primitives/sampler_v2.py b/qiskit_aer/primitives/sampler_v2.py index 4f8c8f52a2..55a80f405a 100644 --- a/qiskit_aer/primitives/sampler_v2.py +++ b/qiskit_aer/primitives/sampler_v2.py @@ -100,9 +100,12 @@ def __init__( self._options = Options(**options) if options else Options() self._backend = AerSimulator(**self.options.backend_options) - def from_backend(self, backend, **options): - """use external backend""" - self._backend.from_backend(backend, **options) + @classmethod + def from_backend(cls, backend, **options): + """make new sampler that uses external backend""" + sampler = cls(**options) + sampler._backend = AerSimulator.from_backend(backend) + return sampler @property def default_shots(self) -> int: @@ -156,6 +159,7 @@ def _run_pub(self, pub: SamplerPub) -> PubResult: for item in meas_info } + metadata = {"shots": pub.shots} if qargs: circuit.measure_all() result = self._backend.run( @@ -181,6 +185,7 @@ def _run_pub(self, pub: SamplerPub) -> PubResult: for item in meas_info: ary = _samples_to_packed_array(samples_array, item.num_bits, item.qreg_indices) arrays[item.creg_name][index] = ary + metadata["simulator_metadata"] = result.metadata else: for index in np.ndenumerate(parameter_values.shape): samples = [""] * pub.shots @@ -199,7 +204,7 @@ def _run_pub(self, pub: SamplerPub) -> PubResult: item.creg_name: BitArray(arrays[item.creg_name], item.num_bits) for item in meas_info } data_bin = data_bin_cls(**meas) - return PubResult(data_bin, metadata={"shots": pub.shots}) + return PubResult(data_bin, metadata=metadata) def _preprocess_circuit(circuit: QuantumCircuit): diff --git a/releasenotes/notes/add_delay_custom_instructions-e1bf80ec3598bfd1.yaml b/releasenotes/notes/add_delay_custom_instructions-e1bf80ec3598bfd1.yaml new file mode 100644 index 0000000000..7a146ce77b --- /dev/null +++ b/releasenotes/notes/add_delay_custom_instructions-e1bf80ec3598bfd1.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Add/move `delay` gate to default custom instructions for `AerSimulator.configulation` + to resolve error reported in issue #2152, `delay` was not in `basis_gates` + when AerSimulator is made by `from_backend` diff --git a/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml new file mode 100644 index 0000000000..9505b6025e --- /dev/null +++ b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + `matrix_product_state`, `extended_stabilizer` and `tensor_network` methods + now support ecr gate. + Add check if `basis_gates` backend option has unsupported gate for + the `method` diff --git a/releasenotes/notes/add_rotation_support-c0ef8155a761e560.yaml b/releasenotes/notes/add_rotation_support-c0ef8155a761e560.yaml new file mode 100644 index 0000000000..34ea800427 --- /dev/null +++ b/releasenotes/notes/add_rotation_support-c0ef8155a761e560.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add `rz` gate with n*pi/2 cases to `extended_stabilizer` method + as well as `stabilizer` method. + + Add `crx`, `cry` and `crz` gates to `statevector` and `tensor_netowork` + methods. diff --git a/releasenotes/notes/add_sampler_v2_simulator_metadata-e17850d483439f9a.yaml b/releasenotes/notes/add_sampler_v2_simulator_metadata-e17850d483439f9a.yaml new file mode 100644 index 0000000000..5fb206b528 --- /dev/null +++ b/releasenotes/notes/add_sampler_v2_simulator_metadata-e17850d483439f9a.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + This fix adds `simulator_metadata` in the `metadata` of `PubResults` + for SamplerV2 primitive as similar to EstimatorV2 primitive diff --git a/releasenotes/notes/fix_enabling_cuStateVec-1a2f1d3e35f3129d.yaml b/releasenotes/notes/fix_enabling_cuStateVec-1a2f1d3e35f3129d.yaml new file mode 100644 index 0000000000..470b010622 --- /dev/null +++ b/releasenotes/notes/fix_enabling_cuStateVec-1a2f1d3e35f3129d.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + The option `cuStateVec_enable=True` was not set correctly. + This fix set this option to statevector, unitary and density_matrix + simulator states classes before allocating their memory diff --git a/releasenotes/notes/fix_issue2084-632a829da1a8dfc5.yaml b/releasenotes/notes/fix_issue2084-632a829da1a8dfc5.yaml new file mode 100644 index 0000000000..6fd3439247 --- /dev/null +++ b/releasenotes/notes/fix_issue2084-632a829da1a8dfc5.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed issue #2084 again. `backend.set_max_qubits` was not + properly implemented. + Also added test case to test this issue. + diff --git a/releasenotes/notes/fix_primitiveV2_init-afe7b331ddbef538.yaml b/releasenotes/notes/fix_primitiveV2_init-afe7b331ddbef538.yaml new file mode 100644 index 0000000000..ba319729a9 --- /dev/null +++ b/releasenotes/notes/fix_primitiveV2_init-afe7b331ddbef538.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed init function of EstimatorV2 and SamplerV2 to set `method` in + its option property if there is no `method` in input parameter diff --git a/releasenotes/notes/fix_stabilizer_measure-a06d761eba2546d2.yaml b/releasenotes/notes/fix_stabilizer_measure-a06d761eba2546d2.yaml new file mode 100644 index 0000000000..b91f95a6f1 --- /dev/null +++ b/releasenotes/notes/fix_stabilizer_measure-a06d761eba2546d2.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fix of deterministic measure of stabilizer and change of OpenMP + parallelization of loop diff --git a/releasenotes/notes/init_omp_first-c9d19dbfa1a0fc2b.yaml b/releasenotes/notes/init_omp_first-c9d19dbfa1a0fc2b.yaml new file mode 100644 index 0000000000..ecf2a49cd4 --- /dev/null +++ b/releasenotes/notes/init_omp_first-c9d19dbfa1a0fc2b.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + In Mac, to use OpenMP, setup of hooks to omp functions is necessary. However, this setup + works only for backend services and not for quantum_info classes of ``AerStatevector`` and + ``AerDensityMatrix``. This fix calls the setup in quantum_info also. diff --git a/setup.py b/setup.py index ba1ef7dcb6..98dad4e2bb 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ extras_requirements = {"dask": ["dask", "distributed"]} requirements = [ - "qiskit>=0.45.0", + "qiskit>=0.45.2", "numpy>=1.16.3", "scipy>=1.0", "psutil>=5", @@ -114,9 +114,4 @@ cmake_args=cmake_args, 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/controller_execute.hpp b/src/controllers/controller_execute.hpp index 88d9c460f1..14f05d67ba 100644 --- a/src/controllers/controller_execute.hpp +++ b/src/controllers/controller_execute.hpp @@ -29,18 +29,15 @@ namespace AER { +void initialize_libraries(const std::string &lib_dir) { + // Fix for MacOS and OpenMP library double initialization crash. + // Issue: https://github.com/Qiskit/qiskit-aer/issues/1 + Hacks::maybe_load_openmp(lib_dir); +} + template Result controller_execute(const inputdata_t &qobj) { controller_t controller; - - // Fix for MacOS and OpenMP library double initialization crash. - // Issue: https://github.com/Qiskit/qiskit-aer/issues/1 - if (Parser::check_key("config", qobj)) { - std::string path; - const auto &config = Parser::get_value("config", qobj); - Parser::get_value(path, "library_dir", config); - Hacks::maybe_load_openmp(path); - } return controller.execute(qobj); } @@ -229,9 +226,6 @@ Result controller_execute(std::vector> &input_circs, auto time_taken = std::chrono::duration(myclock_t::now() - timer_start).count(); - // Fix for MacOS and OpenMP library double initialization crash. - // Issue: https://github.com/Qiskit/qiskit-aer/issues/1 - Hacks::maybe_load_openmp(config.library_dir); controller.set_config(config); auto ret = controller.execute(circs, noise_model, config); diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 484dd3660a..108b008e35 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -724,27 +724,29 @@ inline void check_duplicate_qubits(const Op &op) { } inline void check_gate_params(const Op &op) { - const stringmap_t> param_tables( - {{"u1", {1, 1}}, {"u2", {1, 2}}, {"u3", {1, 3}}, - {"u", {1, 3}}, {"U", {1, 3}}, {"CX", {2, 0}}, - {"cx", {2, 0}}, {"cz", {2, 0}}, {"cy", {2, 0}}, - {"cp", {2, 1}}, {"cu1", {2, 1}}, {"cu2", {2, 2}}, - {"cu3", {2, 3}}, {"swap", {2, 0}}, {"id", {0, 0}}, - {"p", {1, 1}}, {"x", {1, 0}}, {"y", {1, 0}}, - {"z", {1, 0}}, {"h", {1, 0}}, {"s", {1, 0}}, - {"sdg", {1, 0}}, {"t", {1, 0}}, {"tdg", {1, 0}}, - {"r", {1, 2}}, {"rx", {1, 1}}, {"ry", {1, 1}}, - {"rz", {1, 1}}, {"rxx", {2, 1}}, {"ryy", {2, 1}}, - {"rzz", {2, 1}}, {"rzx", {2, 1}}, {"ccx", {3, 0}}, - {"ccz", {3, 0}}, {"cswap", {3, 0}}, {"mcx", {1, 0}}, - {"mcy", {1, 0}}, {"mcz", {1, 0}}, {"mcu1", {1, 1}}, - {"mcu2", {1, 2}}, {"mcu3", {1, 3}}, {"mcswap", {2, 0}}, - {"mcphase", {1, 1}}, {"mcr", {1, 1}}, {"mcrx", {1, 1}}, - {"mcry", {1, 1}}, {"mcrz", {1, 1}}, {"sx", {1, 0}}, - {"sxdg", {1, 0}}, {"csx", {2, 0}}, {"mcsx", {1, 0}}, - {"csxdg", {2, 0}}, {"mcsxdg", {1, 0}}, {"delay", {1, 0}}, - {"pauli", {1, 0}}, {"mcx_gray", {1, 0}}, {"cu", {2, 4}}, - {"mcu", {1, 4}}, {"mcp", {1, 1}}, {"ecr", {2, 0}}}); + const stringmap_t> param_tables({ + {"u1", {1, 1}}, {"u2", {1, 2}}, {"u3", {1, 3}}, + {"u", {1, 3}}, {"U", {1, 3}}, {"CX", {2, 0}}, + {"cx", {2, 0}}, {"cz", {2, 0}}, {"cy", {2, 0}}, + {"cp", {2, 1}}, {"cu1", {2, 1}}, {"cu2", {2, 2}}, + {"cu3", {2, 3}}, {"swap", {2, 0}}, {"id", {0, 0}}, + {"p", {1, 1}}, {"x", {1, 0}}, {"y", {1, 0}}, + {"z", {1, 0}}, {"h", {1, 0}}, {"s", {1, 0}}, + {"sdg", {1, 0}}, {"t", {1, 0}}, {"tdg", {1, 0}}, + {"r", {1, 2}}, {"rx", {1, 1}}, {"ry", {1, 1}}, + {"rz", {1, 1}}, {"rxx", {2, 1}}, {"ryy", {2, 1}}, + {"rzz", {2, 1}}, {"rzx", {2, 1}}, {"ccx", {3, 0}}, + {"ccz", {3, 0}}, {"cswap", {3, 0}}, {"mcx", {1, 0}}, + {"mcy", {1, 0}}, {"mcz", {1, 0}}, {"mcu1", {1, 1}}, + {"mcu2", {1, 2}}, {"mcu3", {1, 3}}, {"mcswap", {2, 0}}, + {"mcphase", {1, 1}}, {"mcr", {1, 1}}, {"mcrx", {1, 1}}, + {"mcry", {1, 1}}, {"mcrz", {1, 1}}, {"sx", {1, 0}}, + {"sxdg", {1, 0}}, {"csx", {2, 0}}, {"mcsx", {1, 0}}, + {"csxdg", {2, 0}}, {"mcsxdg", {1, 0}}, {"delay", {1, 0}}, + {"pauli", {1, 0}}, {"mcx_gray", {1, 0}}, {"cu", {2, 4}}, + {"mcu", {1, 4}}, {"mcp", {1, 1}}, {"ecr", {2, 0}}, + {"crx", {1, 1}}, {"cry", {1, 1}}, {"crz", {1, 1}}, + }); auto it = param_tables.find(op.name); if (it == param_tables.end()) { diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index 5ce6889d49..7210561a32 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -344,6 +344,9 @@ bool State::allocate(uint_t num_qubits, uint_t block_bits, BaseState::qreg_.set_max_sampling_shots(BaseState::max_sampling_shots_); BaseState::qreg_.set_target_gpus(BaseState::target_gpus_); +#ifdef AER_CUSTATEVEC + BaseState::qreg_.cuStateVec_enable(BaseState::cuStateVec_enable_); +#endif BaseState::qreg_.chunk_setup(block_bits * 2, block_bits * 2, 0, 1); return true; diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index cc8c91adf1..9fec5d1656 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -44,9 +44,9 @@ const Operations::OpSet StateOpSet( Operations::OpType::save_statevec, }, // Operations::OpType::save_expval, Operations::OpType::save_expval_var}, // Gates - {"CX", "u0", "u1", "p", "cx", "cz", "swap", "id", - "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", - "t", "tdg", "ccx", "ccz", "delay", "pauli"}); + {"CX", "u0", "u1", "p", "cx", "cz", "swap", "id", + "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", + "t", "tdg", "ccx", "ccz", "delay", "pauli", "ecr", "rz"}); using chpauli_t = CHSimulator::pauli_t; using chstate_t = CHSimulator::Runner; @@ -89,6 +89,9 @@ class State : public QuantumState::State { std::vector sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) override; + bool + validate_parameters(const std::vector &ops) const override; + protected: // Alongside the sample measure optimisaiton, we can parallelise // circuit applicaiton over the states. This reduces the threading overhead @@ -211,6 +214,7 @@ const stringmap_t State::gateset_({ {"sxdg", Gates::sxdg}, // Inverse sqrt(X) gate {"t", Gates::t}, // T-gate (sqrt(S)) {"tdg", Gates::tdg}, // Conjguate-transpose of T gate + {"rz", Gates::rz}, // RZ gate (only support k * pi/2 cases) // Waltz Gates {"u0", Gates::u0}, // idle gate in multiples of X90 {"u1", Gates::u1}, // zero-X90 pulse waltz gate @@ -220,6 +224,7 @@ const stringmap_t State::gateset_({ {"cx", Gates::cx}, // Controlled-X gate (CNOT) {"cz", Gates::cz}, // Controlled-Z gate {"swap", Gates::swap}, // SWAP gate + {"ecr", Gates::ecr}, // ECR Gate // Three-qubit gates {"ccx", Gates::ccx}, // Controlled-CX gate (Toffoli) {"ccz", Gates::ccz}, // Constrolled-CZ gate (H3 Toff H3) @@ -336,6 +341,23 @@ bool State::check_measurement_opt(InputIterator first, return true; } +bool State::validate_parameters(const std::vector &ops) const { + for (uint_t i = 0; i < ops.size(); i++) { + if (ops[i].type == OpType::gate) { + // check parameter of RZ gates + if (ops[i].name == "rz") { + double pi2 = std::real(ops[i].params[0]) * 2.0 / M_PI; + double pi2_int = (double)std::round(pi2); + + if (!AER::Linalg::almost_equal(pi2, pi2_int)) { + return false; + } + } + } + } + return true; +} + //------------------------------------------------------------------------- // Implementation: Operations //------------------------------------------------------------------------- @@ -633,6 +655,7 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng) { } void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) { + int_t pi2; auto it = gateset_.find(op.name); if (it == gateset_.end()) { throw std::invalid_argument("CH::State: Invalid gate operation \'" + @@ -694,6 +717,27 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) { case Gates::pauli: apply_pauli(op.qubits, op.string_params[0], rank); break; + case Gates::ecr: + BaseState::qreg_.apply_s(op.qubits[0], rank); + BaseState::qreg_.apply_sdag(op.qubits[1], rank); + BaseState::qreg_.apply_h(op.qubits[1], rank); + BaseState::qreg_.apply_sdag(op.qubits[1], rank); + BaseState::qreg_.apply_cx(op.qubits[0], op.qubits[1], rank); + BaseState::qreg_.apply_x(op.qubits[0], rank); + break; + case Gates::rz: + pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3; + if (pi2 == 1) { + // S + BaseState::qreg_.apply_s(op.qubits[0], rank); + } else if (pi2 == 2) { + // Z + BaseState::qreg_.apply_z(op.qubits[0], rank); + } else if (pi2 == 3) { + // Sdg + BaseState::qreg_.apply_sdag(op.qubits[0], rank); + } + break; default: // u0 or Identity break; } diff --git a/src/simulators/extended_stabilizer/gates.hpp b/src/simulators/extended_stabilizer/gates.hpp index 3df76b37eb..4f322eea1b 100644 --- a/src/simulators/extended_stabilizer/gates.hpp +++ b/src/simulators/extended_stabilizer/gates.hpp @@ -58,7 +58,9 @@ enum class Gates { swap, ccx, ccz, - pauli + pauli, + ecr, + rz, }; enum class Gatetypes { pauli, clifford, non_clifford }; @@ -80,11 +82,13 @@ const AER::stringmap_t gate_types_ = { {"tdg", Gatetypes::non_clifford}, // Conjguate-transpose of T gate {"u1", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate {"p", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate + {"rz", Gatetypes::clifford}, // RZ gate (only support k * pi/2 cases) // Two-qubit gates {"CX", Gatetypes::clifford}, // Controlled-X gate (CNOT) {"cx", Gatetypes::clifford}, // Controlled-X gate (CNOT) {"cz", Gatetypes::clifford}, // Controlled-Z gate {"swap", Gatetypes::clifford}, // SWAP gate + {"ecr", Gatetypes::clifford}, // ECR Gate // Three-qubit gates {"ccx", Gatetypes::non_clifford}, // Controlled-CX gate (Toffoli) {"ccz", Gatetypes::non_clifford}, // Controlled-CZ gate (H3 Toff H3) diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 51df5dd27e..1cfeb9b43d 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -75,10 +75,10 @@ const Operations::OpSet StateOpSet( OpType::jump, OpType::mark}, // Gates - {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", - "u1", "u2", "u3", "u", "U", "CX", "cx", "cy", "cz", "cp", - "cu1", "swap", "ccx", "sx", "sxdg", "r", "rx", "ry", "rz", "rxx", - "ryy", "rzz", "rzx", "csx", "delay", "cswap", "pauli"}); + {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", + "u1", "u2", "u3", "u", "U", "CX", "cx", "cy", "cz", "cp", + "cu1", "swap", "ccx", "sx", "sxdg", "r", "rx", "ry", "rz", "rxx", + "ryy", "rzz", "rzx", "csx", "delay", "cswap", "pauli", "ecr"}); //========================================================================= // Matrix Product State subclass @@ -296,6 +296,7 @@ const stringmap_t {"ryy", Gates::ryy}, // Pauli-YY rotation gate {"rzz", Gates::rzz}, // Pauli-ZZ rotation gate {"rzx", Gates::rzx}, // Pauli-ZX rotation gate + {"ecr", Gates::ecr}, // ECR Gate /* Three-qubit gates */ {"ccx", Gates::ccx}, // Controlled-CX gate (Toffoli) {"cswap", Gates::cswap}, @@ -673,6 +674,9 @@ void State::apply_gate(const Operations::Op &op) { case Gates::pauli: apply_pauli(op.qubits, op.string_params[0]); break; + case Gates::ecr: + qreg_.apply_matrix(op.qubits, Linalg::Matrix::ECR); + break; default: // We shouldn't reach here unless there is a bug in gateset throw std::invalid_argument( diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp index e6a82c28cc..1180e6cddf 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -58,7 +58,8 @@ enum Gates { csx, // two qubit ccx, cswap, // three qubit - pauli + pauli, + ecr, }; // enum class Direction {RIGHT, LEFT}; diff --git a/src/simulators/parallel_state_executor.hpp b/src/simulators/parallel_state_executor.hpp index cbae13f521..0635da9ef5 100644 --- a/src/simulators/parallel_state_executor.hpp +++ b/src/simulators/parallel_state_executor.hpp @@ -339,6 +339,7 @@ bool ParallelStateExecutor::allocate_states(uint_t num_states, Base::num_threads_per_group_); Base::states_[0].set_num_global_qubits(Base::num_qubits_); #ifdef AER_CUSTATEVEC + Base::states_[0].enable_cuStateVec(Base::cuStateVec_enable_); Base::states_[0].qreg().cuStateVec_enable(Base::cuStateVec_enable_); #endif Base::states_[0].qreg().set_target_gpus(Base::target_gpus_); @@ -346,6 +347,9 @@ bool ParallelStateExecutor::allocate_states(uint_t num_states, squbits, gqubits, Base::global_state_index_, num_states); for (i = 1; i < num_states_allocated; i++) { Base::states_[i].set_config(config); +#ifdef AER_CUSTATEVEC + Base::states_[i].enable_cuStateVec(Base::cuStateVec_enable_); +#endif Base::states_[i].qreg().chunk_setup(Base::states_[0].qreg(), Base::global_state_index_ + i); Base::states_[i].qreg().set_num_threads_per_group( diff --git a/src/simulators/stabilizer/clifford.hpp b/src/simulators/stabilizer/clifford.hpp index 568413d810..506ebf37fe 100644 --- a/src/simulators/stabilizer/clifford.hpp +++ b/src/simulators/stabilizer/clifford.hpp @@ -456,9 +456,8 @@ bool Clifford::measure_and_update(const uint64_t qubit, t0 = rX & destabilizer_table_[q].Z(i); t1 = rZ ^ destabilizer_table_[q].X(i); - t1 ^= t0; - d1 ^= (t0 & d0); + d1 ^= (t0 & (~d0)); d0 ^= t0; d1 ^= (t0 & t1); @@ -475,9 +474,8 @@ bool Clifford::measure_and_update(const uint64_t qubit, t0 = rX & stabilizer_table_[q].Z(i); t1 = rZ ^ stabilizer_table_[q].X(i); - t1 ^= t0; - s1 ^= (t0 & s0); + s1 ^= (t0 & (~s0)); s0 ^= t0; s1 ^= (t0 & t1); @@ -515,127 +513,79 @@ bool Clifford::measure_and_update(const uint64_t qubit, } else { // Deterministic outcome uint_t outcome = 0; - Pauli::Pauli accum(num_qubits_); uint_t blocks = destabilizer_phases_.blockLength(); - if (blocks < 2) { + auto measure_determinisitic_func = [this, blocks, qubit](AER::int_t q) { + uint_t accumX = 0; + uint_t accumZ = 0; + uint_t exponent_l = 0ull; + uint_t exponent_h = 0ull; + bool accumX_prev = false; + bool accumZ_prev = false; + for (uint_t ib = 0; ib < blocks; ib++) { + uint_t tl, th, add; uint_t destabilizer_mask = destabilizer_table_[qubit].X(ib); - uint_t exponent_l = 0ull; - uint_t exponent_h = 0ull; - - for (uint_t q = 0; q < num_qubits_; q++) { - uint_t tl, th, add; - uint_t accumX = 0ull - (uint_t)accum.X[q]; - uint_t accumZ = 0ull - (uint_t)accum.Z[q]; - - tl = accumX & stabilizer_table_[q].Z(ib); - th = accumZ ^ stabilizer_table_[q].X(ib); - - add = tl & exponent_l; - exponent_l ^= tl; - exponent_h ^= add; - exponent_h ^= (tl & th); - - tl = stabilizer_table_[q].X(ib) & accumZ; - th = stabilizer_table_[q].Z(ib) ^ accumX; - th ^= tl; - - add = tl & exponent_l; - exponent_l ^= tl; - exponent_h ^= add; - exponent_h ^= (tl & th); - - add = stabilizer_table_[q].X(ib) & destabilizer_mask; - accumX &= AER::Utils::popcount(add) & 1; - add = stabilizer_table_[q].Z(ib) & destabilizer_mask; - accumZ &= AER::Utils::popcount(add) & 1; - - accum.X.setValue((bool)accumX, q); - accum.Z.setValue((bool)accumZ, q); - } - exponent_h ^= stabilizer_phases_(ib); - outcome ^= (exponent_h & destabilizer_mask); - if ((exponent_l & destabilizer_mask) != 0) { - throw std::runtime_error("Clifford: rowsum error"); - } - } - } else { - uint_t blockSize = destabilizer_phases_.blockSize(); - - // loop for cache blocking - for (uint_t ii = 0; ii < blocks; ii++) { - uint_t destabilizer_mask = destabilizer_table_[qubit].X(ii); - if (destabilizer_mask == 0) - continue; - - uint_t exponent_l = 0; - uint_t exponent_lc = 0; - uint_t exponent_h = 0; - - auto measure_determinisitic_func = - [this, &accum, &exponent_l, &exponent_lc, &exponent_h, blocks, - blockSize, destabilizer_mask, ii](AER::int_t qq) { - uint_t qs = qq * blockSize; - uint_t qe = qs + blockSize; - if (qe > num_qubits_) - qe = num_qubits_; - - uint_t local_exponent_l = 0; - uint_t local_exponent_h = 0; - - for (uint_t q = qs; q < qe; q++) { - uint_t sX = stabilizer_table_[q].X(ii); - uint_t sZ = stabilizer_table_[q].Z(ii); - - uint_t accumX = (0ull - (uint_t)accum.X[q]); - uint_t accumZ = (0ull - (uint_t)accum.Z[q]); - - // exponents for this block - uint_t t0, t1; - - t0 = accumX & sZ; - t1 = accumZ ^ sX; - - local_exponent_h ^= (t0 & local_exponent_l); - local_exponent_l ^= t0; - local_exponent_h ^= (t0 & t1); - - t0 = sX & accumZ; - t1 = sZ ^ accumX; - t1 ^= t0; - - local_exponent_h ^= (t0 & local_exponent_l); - local_exponent_l ^= t0; - local_exponent_h ^= (t0 & t1); - - // update accum - accumX &= AER::Utils::popcount(sX & destabilizer_mask) & 1; - accum.X.setValue((accumX != 0), q); - accumZ &= AER::Utils::popcount(sZ & destabilizer_mask) & 1; - accum.Z.setValue((accumZ != 0), q); - } - -#pragma omp atomic - exponent_lc |= local_exponent_l; -#pragma omp atomic - exponent_l ^= local_exponent_l; -#pragma omp atomic - exponent_h ^= local_exponent_h; - }; - AER::Utils::apply_omp_parallel_for( - (num_qubits_ > omp_threshold_ && omp_threads_ > 1 && nid == 1), 0, - blocks, measure_determinisitic_func, omp_threads_); - - // if exponent_l is 0 and any of local_exponent_l is - // 1, then flip exponent_h - exponent_h ^= (exponent_lc ^ exponent_l); - exponent_h ^= stabilizer_phases_(ii); - outcome ^= (exponent_h & destabilizer_mask); + uint_t sX = stabilizer_table_[q].X(ib) & destabilizer_mask; + uint_t sZ = stabilizer_table_[q].Z(ib) & destabilizer_mask; + + // accumulate for 64 bits block + accumX = sX ^ (uint_t)accumX_prev; + accumZ = sZ ^ (uint_t)accumZ_prev; + accumX ^= (accumX << 1); + accumZ ^= (accumZ << 1); + accumX ^= (accumX << 2); + accumZ ^= (accumZ << 2); + accumX ^= (accumX << 4); + accumZ ^= (accumZ << 4); + accumX ^= (accumX << 8); + accumZ ^= (accumZ << 8); + accumX ^= (accumX << 16); + accumZ ^= (accumZ << 16); + accumX ^= (accumX << 32); + accumZ ^= (accumZ << 32); + // store for next iteration + accumX_prev = ((accumX >> 63) & 1) != 0; + accumZ_prev = ((accumZ >> 63) & 1) != 0; + // correct for this iteration + accumX ^= sX; + accumZ ^= sZ; + accumX &= destabilizer_mask; + accumZ &= destabilizer_mask; + + tl = accumX & sZ; + th = accumZ ^ sX; + + add = tl & exponent_l; + exponent_l ^= tl; + exponent_h ^= add; + exponent_h ^= (tl & th); + + tl = sX & accumZ; + th = sZ ^ accumX; + + add = tl & (~exponent_l); + exponent_l ^= tl; + exponent_h ^= add; + exponent_h ^= (tl & th); } + // convert 2-bits x 64 integer into bit count here + return AER::Utils::popcount(exponent_h) * 2 + + AER::Utils::popcount(exponent_l); + }; + + outcome = AER::Utils::apply_omp_parallel_for_reduction_int( + (num_qubits_ > omp_threshold_ && omp_threads_ > 1 && nid == 1), 0, + num_qubits_, measure_determinisitic_func, omp_threads_); + + uint_t stab_h = 0ull; + for (uint_t ib = 0; ib < blocks; ib++) { + stab_h ^= (destabilizer_table_[qubit].X(ib) & stabilizer_phases_(ib)); } - return ((AER::Utils::popcount(outcome) & 1) != 0); + outcome += AER::Utils::popcount(stab_h) * 2; + + return ((outcome & 3) == 2); } } diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index cd0e18f678..8be6b380be 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -38,8 +38,8 @@ const Operations::OpSet StateOpSet( OpType::save_amps_sq, OpType::save_stabilizer, OpType::save_clifford, OpType::save_state, OpType::set_stabilizer, OpType::jump, OpType::mark}, // Gates - {"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", - "s", "sdg", "sx", "sxdg", "delay", "pauli", "ecr", "rx", "ry", "rz"}); + {"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "sx", + "sxdg", "delay", "pauli", "ecr", "rz"}); enum class Gates { id, @@ -57,8 +57,6 @@ enum class Gates { swap, pauli, ecr, - rx, - ry, rz }; @@ -202,6 +200,7 @@ const stringmap_t State::gateset_({ {"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2)) {"sx", Gates::sx}, // Sqrt X gate. {"sxdg", Gates::sxdg}, // Inverse Sqrt X gate. + {"rz", Gates::rz}, // RZ gate (only support k * pi/2 cases) // Two-qubit gates {"CX", Gates::cx}, // Controlled-X gate (CNOT) {"cx", Gates::cx}, // Controlled-X gate (CNOT), @@ -210,9 +209,6 @@ const stringmap_t State::gateset_({ {"swap", Gates::swap}, // SWAP gate {"pauli", Gates::pauli}, // Pauli gate {"ecr", Gates::ecr}, // ECR gate - {"rx", Gates::rx}, // RX gate (only support k * pi/2 cases) - {"ry", Gates::ry}, // RY gate (only support k * pi/2 cases) - {"rz", Gates::rz} // RZ gate (only support k * pi/2 cases) }); //============================================================================ @@ -257,8 +253,8 @@ void State::set_config(const Config &config) { bool State::validate_parameters(const std::vector &ops) const { 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") { + // check parameter of RZ gates + if (ops[i].name == "rz") { double pi2 = std::real(ops[i].params[0]) * 2.0 / M_PI; double pi2_int = (double)std::round(pi2); @@ -387,45 +383,14 @@ void State::apply_gate(const Operations::Op &op) { apply_pauli(op.qubits, op.string_params[0]); break; case Gates::ecr: - BaseState::qreg_.append_h(op.qubits[1]); BaseState::qreg_.append_s(op.qubits[0]); - BaseState::qreg_.append_z(op.qubits[1]); // sdg(1) - BaseState::qreg_.append_s(op.qubits[1]); // sdg(1) + BaseState::qreg_.append_z(op.qubits[1]); + BaseState::qreg_.append_s(op.qubits[1]); BaseState::qreg_.append_h(op.qubits[1]); + BaseState::qreg_.append_z(op.qubits[1]); + BaseState::qreg_.append_s(op.qubits[1]); BaseState::qreg_.append_cx(op.qubits[0], op.qubits[1]); BaseState::qreg_.append_x(op.qubits[0]); - BaseState::qreg_.append_x(op.qubits[1]); - break; - case Gates::rx: - pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3; - if (pi2 == 1) { - // HSH - BaseState::qreg_.append_h(op.qubits[0]); - BaseState::qreg_.append_s(op.qubits[0]); - BaseState::qreg_.append_h(op.qubits[0]); - } else if (pi2 == 2) { - // X - BaseState::qreg_.append_x(op.qubits[0]); - } else if (pi2 == 3) { - // HSdgH - BaseState::qreg_.append_h(op.qubits[0]); - BaseState::qreg_.append_z(op.qubits[0]); - BaseState::qreg_.append_s(op.qubits[0]); - BaseState::qreg_.append_h(op.qubits[0]); - } - break; - case Gates::ry: - pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3; - if (pi2 == 1) { - 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) { - BaseState::qreg_.append_x(op.qubits[0]); - BaseState::qreg_.append_h(op.qubits[0]); - } break; case Gates::rz: pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3; diff --git a/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp b/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp index 4baad583da..7da1fc75e2 100644 --- a/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp +++ b/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp @@ -131,7 +131,6 @@ uint_t cuStateVecChunkContainer::Allocate( nc = BaseContainer::Allocate(idev, chunk_bits, num_qubits, chunks, buffers, multi_shots, matrix_bit, max_shots, density_matrix); - // initialize custatevevtor handle custatevecStatus_t err; diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 8907bb974c..b47dce1bda 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -66,14 +66,17 @@ const Operations::OpSet StateOpSet( OpType::jump, OpType::mark}, // Gates - {"u1", "u2", "u3", "u", "U", "CX", "cx", "cz", - "cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p", - "x", "y", "z", "h", "s", "sdg", "t", "tdg", - "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", - "ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", - "mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", - "csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu", - "mcu", "mcp", "ecr", "mcphase"}); + { + "u1", "u2", "u3", "u", "U", "CX", "cx", + "cz", "cy", "cp", "cu1", "cu2", "cu3", "swap", + "id", "p", "x", "y", "z", "h", "s", + "sdg", "t", "tdg", "r", "rx", "ry", "rz", + "rxx", "ryy", "rzz", "rzx", "ccx", "ccz", "cswap", + "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", + "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", "csx", + "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu", + "mcu", "mcp", "ecr", "mcphase", "crx", "cry", "crz", + }); // Allowed gates enum class enum class Gates { @@ -368,6 +371,9 @@ const stringmap_t State::gateset_( {"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate {"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate {"ecr", Gates::ecr}, // ECR Gate + {"crx", Gates::mcrx}, // Controlled X-rotation gate + {"cry", Gates::mcry}, // Controlled Y-rotation gate + {"crz", Gates::mcrz}, // Controlled Z-rotation gate /* 3-qubit gates */ {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) {"ccz", Gates::mcz}, // Controlled-CZ gate @@ -439,6 +445,9 @@ bool State::allocate(uint_t num_qubits, uint_t block_bits, BaseState::qreg_.set_max_sampling_shots(BaseState::max_sampling_shots_); BaseState::qreg_.set_target_gpus(BaseState::target_gpus_); +#ifdef AER_CUSTATEVEC + BaseState::qreg_.cuStateVec_enable(BaseState::cuStateVec_enable_); +#endif BaseState::qreg_.chunk_setup(block_bits, num_qubits, 0, 1); return true; diff --git a/src/simulators/tensor_network/tensor_net_state.hpp b/src/simulators/tensor_network/tensor_net_state.hpp index 573d5973be..d8524dfe25 100644 --- a/src/simulators/tensor_network/tensor_net_state.hpp +++ b/src/simulators/tensor_network/tensor_net_state.hpp @@ -72,9 +72,9 @@ const Operations::OpSet StateOpSet( "sdg", "t", "tdg", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", "ccx", "ccz", "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase", - "mcr", "mcrx", "mcry", "mcry", "sx", "sxdg", "csx", + "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", "csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu", - "mcu", "mcp", "ecr", "cswap"}); + "mcu", "mcp", "ecr", "cswap", "crx", "cry", "crz"}); // Allowed gates enum class enum class Gates { @@ -361,6 +361,9 @@ const stringmap_t State::gateset_( {"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate {"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate {"ecr", Gates::ecr}, // ECR Gate + {"crx", Gates::mcrx}, // Controlled X-rotation gate + {"cry", Gates::mcry}, // Controlled Y-rotation gate + {"crz", Gates::mcrz}, // Controlled Z-rotation gate /* 3-qubit gates */ {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) {"ccz", Gates::mcz}, // Controlled-CZ gate diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index ab0ca636f4..3c3ba3d2af 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -41,14 +41,16 @@ const Operations::OpSet StateOpSet( Operations::OpType::save_state, Operations::OpType::set_unitary, Operations::OpType::jump, Operations::OpType::mark}, // Gates - {"u1", "u2", "u3", "u", "U", "CX", "cx", "cz", - "cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p", - "x", "y", "z", "h", "s", "sdg", "t", "tdg", - "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", - "ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", - "mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcry", "sx", "sxdg", - "csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "cu", "mcu", - "mcp", "ecr", "mcphase"}); + { + "u1", "u2", "u3", "u", "U", "CX", "cx", "cz", + "cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p", + "x", "y", "z", "h", "s", "sdg", "t", "tdg", + "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", + "ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", + "mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", + "csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "cu", "mcu", + "mcp", "ecr", "mcphase", "crx", "cry", "crz", + }); // Allowed gates enum class enum class Gates { @@ -253,6 +255,9 @@ const stringmap_t State::gateset_({ {"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate {"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate {"ecr", Gates::ecr}, // ECR Gate + {"crx", Gates::mcrx}, // Controlled X-rotation gate + {"cry", Gates::mcry}, // Controlled Y-rotation gate + {"crz", Gates::mcrz}, // Controlled Z-rotation gate // Three-qubit gates {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) {"ccz", Gates::mcz}, // Controlled-CZ gate @@ -383,6 +388,9 @@ bool State::allocate(uint_t num_qubits, uint_t block_bits, BaseState::qreg_.set_max_matrix_bits(BaseState::max_matrix_qubits_); BaseState::qreg_.set_target_gpus(BaseState::target_gpus_); +#ifdef AER_CUSTATEVEC + BaseState::qreg_.cuStateVec_enable(BaseState::cuStateVec_enable_); +#endif BaseState::qreg_.chunk_setup(block_bits * 2, num_qubits * 2, 0, 1); return true; diff --git a/test/terra/backends/aer_simulator/test_chunk.py b/test/terra/backends/aer_simulator/test_chunk.py index ca4c20d90b..23dad5589d 100644 --- a/test/terra/backends/aer_simulator/test_chunk.py +++ b/test/terra/backends/aer_simulator/test_chunk.py @@ -32,6 +32,7 @@ class TestChunkSimulators(SimulatorTestCase): def test_chunk_QuantumVolume(self, method, device): """Test multi-chunk with quantum volume""" opts = {"blocking_enable": True, "blocking_qubits": 2} + opts["basis_gates"] = ["h", "cx", "u3"] backend = self.backend(method=method, device=device, **opts) backend_no_chunk = self.backend(method=method, device=device) @@ -57,10 +58,12 @@ def test_chunk_QuantumVolumeWithFusion(self, method, device): opts_no_chunk = { "fusion_enable": True, "fusion_threshold": 5, + "fusion_max_qubit": 4, } opts_chunk = copy.copy(opts_no_chunk) opts_chunk["blocking_enable"] = True - opts_chunk["blocking_qubits"] = 4 + opts_chunk["blocking_qubits"] = 5 + opts_chunk["basis_gates"] = ["h", "cx", "u3"] backend = self.backend(method=method, device=device, **opts_chunk) backend_no_chunk = self.backend(method=method, device=device, **opts_no_chunk) diff --git a/test/terra/backends/aer_simulator/test_cliffords.py b/test/terra/backends/aer_simulator/test_cliffords.py index b6c430ae0e..4a92ba27fa 100644 --- a/test/terra/backends/aer_simulator/test_cliffords.py +++ b/test/terra/backends/aer_simulator/test_cliffords.py @@ -16,6 +16,7 @@ from test.terra.reference import ref_1q_clifford from test.terra.reference import ref_2q_clifford from qiskit import transpile +from qiskit import QuantumCircuit from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods SUPPORTED_METHODS = [ @@ -28,10 +29,6 @@ "tensor_network", ] -SUPPORTED_ECR_METHODS = [ - "stabilizer", -] - @ddt class TestCliffords(SimulatorTestCase): @@ -249,11 +246,11 @@ def test_pauli_gate_deterministic(self, method, device): # --------------------------------------------------------------------- # Test ecr gate # --------------------------------------------------------------------- - @supported_methods(SUPPORTED_ECR_METHODS) + @supported_methods(SUPPORTED_METHODS) def test_ecr_gate_nondeterministic(self, method, device): """Test ecr gate circuits""" backend = self.backend(method=method, device=device, seed_simulator=self.SEED) - shots = 100 + shots = 1000 circuits = ref_2q_clifford.ecr_gate_circuits_nondeterministic(final_measure=True) targets = ref_2q_clifford.ecr_gate_counts_nondeterministic(shots) result = backend.run(circuits, shots=shots).result() diff --git a/test/terra/backends/aer_simulator/test_control_flow.py b/test/terra/backends/aer_simulator/test_control_flow.py index 9660b7856f..31596a92bb 100644 --- a/test/terra/backends/aer_simulator/test_control_flow.py +++ b/test/terra/backends/aer_simulator/test_control_flow.py @@ -214,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", "stabilizer") + @data("statevector", "density_matrix", "matrix_product_state") def test_for_loop_builder(self, method): backend = self.backend(method=method) @@ -266,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", "stabilizer") + @data("statevector", "density_matrix", "matrix_product_state") def test_for_loop_break_builder(self, method): backend = self.backend(method=method) @@ -309,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", "stabilizer") + @data("statevector", "density_matrix", "matrix_product_state") def test_for_loop_continue_builder(self, method): backend = self.backend(method=method) @@ -486,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", "stabilizer") + @data("statevector", "density_matrix", "matrix_product_state") def test_nested_loop(self, method): backend = self.backend(method=method) diff --git a/test/terra/backends/aer_simulator/test_measure.py b/test/terra/backends/aer_simulator/test_measure.py index 72356e5f89..4d401d802b 100644 --- a/test/terra/backends/aer_simulator/test_measure.py +++ b/test/terra/backends/aer_simulator/test_measure.py @@ -284,6 +284,38 @@ def test_measure_sampling_large_ghz_stabilizer(self, method, device, num_qubits) targets["1" * num_qubits] = shots / 2 self.assertDictAlmostEqual(counts, targets, delta=delta * shots) + @supported_methods(["stabilizer"]) + def test_measure_stablizer_deterministic(self, method, device): + """Test stabilizer measure for deterministic case""" + backend = self.backend(method=method, device=device) + shots = 10000 + qc = QuantumCircuit(5, 1) + qc.h([2, 4]) + qc.cx(2, 0) + qc.s(0) + qc.cx(4, 2) + qc.h(0) + qc.cx(2, 3) + qc.s(4) + qc.cx(1, 0) + qc.h([3, 4]) + qc.cx(3, 2) + qc.h(3) + qc.cx(0, 3) + qc.cx(3, 1) + qc.s(0) + qc.s(1) + qc.h(0) + qc.s(0) + qc.cx(4, 0) + qc.cx(0, 1) + qc.measure(1, 0) + result = backend.run(qc, shots=shots).result() + counts = result.get_counts() + self.assertSuccess(result) + + self.assertDictEqual(counts, {"1": shots}) + # --------------------------------------------------------------------- # Test MPS algorithms for measure # --------------------------------------------------------------------- diff --git a/test/terra/backends/aer_simulator/test_rotation.py b/test/terra/backends/aer_simulator/test_rotation.py index 9e9c2982ef..4f9eb3dfb8 100644 --- a/test/terra/backends/aer_simulator/test_rotation.py +++ b/test/terra/backends/aer_simulator/test_rotation.py @@ -18,12 +18,21 @@ from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods SUPPORTED_METHODS = [ + "automatic", + "statevector", + "density_matrix", + "matrix_product_state", + "tensor_network", +] + +SUPPORTED_METHODS_RZ = [ "automatic", "stabilizer", "statevector", "density_matrix", "matrix_product_state", "tensor_network", + "extended_stabilizer", ] @@ -50,7 +59,7 @@ def test_rx_gate_deterministic(self, method, device): # --------------------------------------------------------------------- # Test rz-gate # --------------------------------------------------------------------- - @supported_methods(SUPPORTED_METHODS) + @supported_methods(SUPPORTED_METHODS_RZ) def test_rz_gate_deterministic(self, method, device): """Test rz-gate circuits""" backend = self.backend(method=method, device=device, seed_simulator=self.SEED) diff --git a/test/terra/backends/aer_simulator/test_shot_branching.py b/test/terra/backends/aer_simulator/test_shot_branching.py index ac3ff0a810..32b0547763 100644 --- a/test/terra/backends/aer_simulator/test_shot_branching.py +++ b/test/terra/backends/aer_simulator/test_shot_branching.py @@ -12,6 +12,8 @@ """ AerSimulator Integration Tests """ +import unittest +import platform from ddt import ddt from test.terra.reference import ref_measure @@ -47,7 +49,6 @@ import numpy as np - SUPPORTED_METHODS = [ "statevector", "density_matrix", @@ -60,6 +61,7 @@ @ddt +@unittest.skipIf(platform.system() == "Darwin", "skip MacOS tentatively") class TestShotBranching(SimulatorTestCase): """AerSimulator measure tests.""" diff --git a/test/terra/backends/test_parameterized_qobj.py b/test/terra/backends/test_parameterized_qobj.py index e08c697ccf..b37f2d981e 100644 --- a/test/terra/backends/test_parameterized_qobj.py +++ b/test/terra/backends/test_parameterized_qobj.py @@ -213,7 +213,9 @@ def test_run_path_with_more_params_than_expressions(self): circuit.ry(phi, 1) circuit.measure_all() parameter_binds = [{theta: [0, pi, 2 * pi], phi: [0, 1, pi]}] - res = backend.run(circuit, shots=shots, parameter_binds=parameter_binds).result() + res = backend.run( + circuit, shots=shots, parameter_binds=parameter_binds, **self.BACKEND_OPTS + ).result() counts = res.get_counts() for index, expected in enumerate( [{"00": shots}, {"01": 0.25 * shots, "11": 0.75 * shots}, {"10": shots}] @@ -317,7 +319,9 @@ def test_run_path_with_more_params_than_expressions_multiple_circuits(self): circuit.ry(phi, 1) circuit.measure_all() parameter_binds = [{theta: [0, pi, 2 * pi], phi: [0, 1, pi]}] * 3 - res = backend.run([circuit] * 3, shots=shots, parameter_binds=parameter_binds).result() + res = backend.run( + [circuit] * 3, shots=shots, parameter_binds=parameter_binds, **self.BACKEND_OPTS + ).result() counts = res.get_counts() for index, expected in enumerate( [{"00": shots}, {"01": 0.25 * shots, "11": 0.75 * shots}, {"10": shots}] * 3 @@ -461,7 +465,7 @@ def test_check_parameter_binds_exist(self): def test_global_phase_parameters(self): """Test parameterized global phase""" - backend = AerSimulator(method="extended_stabilizer") + backend = AerSimulator(method="extended_stabilizer", basis_gates=["h", "x", "u1"]) theta = Parameter("theta") circ = QuantumCircuit(2) diff --git a/test/terra/backends/test_runtime_parameterization.py b/test/terra/backends/test_runtime_parameterization.py index e2c8af659f..24f8f0e4c3 100644 --- a/test/terra/backends/test_runtime_parameterization.py +++ b/test/terra/backends/test_runtime_parameterization.py @@ -15,6 +15,7 @@ """ import unittest +import platform from math import pi from ddt import ddt import numpy as np @@ -593,6 +594,7 @@ def test_dynamic_circuit(self, method, device): self.assertEqual(counts, counts_pre_bind) @supported_methods(SUPPORTED_METHODS) + @unittest.skipIf(platform.system() == "Darwin", "skip MacOS tentatively") def test_dynamic_circuit_with_shot_branching(self, method, device): """Test parameterized dynamic circuit""" shots = 1000 @@ -746,6 +748,7 @@ def test_kraus_noise(self, method, device): self.assertEqual(counts, counts_pre_bind) @supported_methods(SUPPORTED_METHODS) + @unittest.skipIf(platform.system() == "Darwin", "skip MacOS tentatively") def test_pauli_noise_with_shot_branching(self, method, device): """Test parameterized circuit with Pauli noise""" shots = 1000 @@ -790,6 +793,7 @@ def test_pauli_noise_with_shot_branching(self, method, device): self.assertEqual(counts, counts_pre_bind) @supported_methods(SUPPORTED_METHODS) + @unittest.skipIf(platform.system() == "Darwin", "skip MacOS tentatively") def test_kraus_noise_with_shot_branching(self, method, device): """Test parameterized circuit with Kraus noise""" shots = 1000 diff --git a/test/terra/primitives/test_sampler.py b/test/terra/primitives/test_sampler.py index 0bb0bb1bb6..2ecc27c528 100644 --- a/test/terra/primitives/test_sampler.py +++ b/test/terra/primitives/test_sampler.py @@ -270,6 +270,16 @@ def test_multiple_cregs(self): result = Sampler().run(qc, shots=100).result() self.assertDictAlmostEqual(result.quasi_dists[0], {0: 1}) + def test_truncate_large_circuit(self): + """Test trancate large circuit in transplier""" + sampler = Sampler() + qc = QuantumCircuit(100, 2) + qc.h(98) + qc.cx(98, 99) + qc.measure([98, 99], [0, 1]) + result = sampler.run(qc).result() + self.assertIsInstance(result, SamplerResult) + if __name__ == "__main__": unittest.main() diff --git a/test/terra/primitives/test_sampler_v2.py b/test/terra/primitives/test_sampler_v2.py index 0fe645e263..ecf9cc6048 100644 --- a/test/terra/primitives/test_sampler_v2.py +++ b/test/terra/primitives/test_sampler_v2.py @@ -513,6 +513,12 @@ def test_circuit_with_unitary(self): self.assertEqual(len(result), 1) self._assert_allclose(result[0].data.meas, np.array({1: self._shots})) + def get_data_bin_len(self, data): + if "keys" in dir(data): # qiskit 1.1 or later + return len(data.keys()) + else: + return len(astuple(data)) + def test_circuit_with_multiple_cregs(self): """Test for circuit with multiple classical registers.""" cases = [] @@ -581,7 +587,7 @@ def test_circuit_with_multiple_cregs(self): result = sampler.run([qc], shots=self._shots).result() self.assertEqual(len(result), 1) data = result[0].data - self.assertEqual(len(astuple(data)), 3) + self.assertEqual(self.get_data_bin_len(data), 3) for creg in qc.cregs: self.assertTrue(hasattr(data, creg.name)) self._assert_allclose(getattr(data, creg.name), np.array(target[creg.name])) @@ -614,7 +620,7 @@ def test_circuit_with_aliased_cregs(self): result = sampler.run([qc2], shots=self._shots).result() self.assertEqual(len(result), 1) data = result[0].data - self.assertEqual(len(astuple(data)), 3) + self.assertEqual(self.get_data_bin_len(data), 3) for creg_name in target: self.assertTrue(hasattr(data, creg_name)) self._assert_allclose(getattr(data, creg_name), np.array(target[creg_name])) diff --git a/test/terra/reference/ref_2q_clifford.py b/test/terra/reference/ref_2q_clifford.py index 59cc2b0629..e368984eca 100644 --- a/test/terra/reference/ref_2q_clifford.py +++ b/test/terra/reference/ref_2q_clifford.py @@ -109,6 +109,14 @@ def cx_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) + # test ctrl_states=0 + circuit = QuantumCircuit(*regs) + circuit.cx(qr[0], qr[1], ctrl_state=0) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + return circuits @@ -132,6 +140,8 @@ def cx_gate_counts_deterministic(shots, hex_counts=True): targets.append({"0x1": shots}) # {"00": shots} # CX10.(X^X), |10> state targets.append({"0x2": shots}) # {"00": shots} + # test ctrl_states=0 + targets.append({"0x2": shots}) # {"00": shots} else: # CX01, |00> state targets.append({"00": shots}) # {"00": shots} @@ -149,6 +159,8 @@ def cx_gate_counts_deterministic(shots, hex_counts=True): targets.append({"01": shots}) # {"00": shots} # CX10.(X^X), |10> state targets.append({"10": shots}) # {"00": shots} + # test ctrl_states=0 + targets.append({"10": shots}) # {"00": shots} return targets @@ -225,6 +237,16 @@ def cx_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) + + # test ctrl_states=0 + circuit = QuantumCircuit(*regs) + circuit.h(qr[0]) + circuit.cx(qr[0], qr[1], ctrl_state=0) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + return circuits @@ -236,11 +258,15 @@ def cx_gate_counts_nondeterministic(shots, hex_counts=True): targets.append({"0x0": shots / 2, "0x3": shots / 2}) # CX10.(I^H), Bell state targets.append({"0x0": shots / 2, "0x3": shots / 2}) + # test ctrl_states=0 + targets.append({"0x1": shots / 2, "0x2": shots / 2}) else: # CX01.(I^H), Bell state targets.append({"00": shots / 2, "11": shots / 2}) # CX10.(I^H), Bell state targets.append({"00": shots / 2, "11": shots / 2}) + # test ctrl_states=0 + targets.append({"01": shots / 2, "10": shots / 2}) return targets diff --git a/test/terra/states/test_aer_densitymatrix.py b/test/terra/states/test_aer_densitymatrix.py index 61aacb20cc..683a9856ed 100644 --- a/test/terra/states/test_aer_densitymatrix.py +++ b/test/terra/states/test_aer_densitymatrix.py @@ -145,12 +145,13 @@ def test_QFT(self): self.assertEqual(1, len(counts)) self.assertTrue("0000" in counts) - def test_single_qubit_QV(self): + def test_two_qubit_QV(self): """Test single qubit QuantumVolume""" - state = AerDensityMatrix(QuantumVolume(1)) + state = AerDensityMatrix(QuantumVolume(2, seed=1111)) + state.seed(1111) counts = state.sample_counts(shots=1024) - self.assertEqual(1, len(counts)) - self.assertTrue("0" in counts) + self.assertEqual(4, len(counts)) + self.assertTrue("00" in counts) def test_evolve(self): """Test evolve method for circuits""" diff --git a/test/terra/states/test_aer_statevector.py b/test/terra/states/test_aer_statevector.py index 0a78d681d5..0b11b1681d 100644 --- a/test/terra/states/test_aer_statevector.py +++ b/test/terra/states/test_aer_statevector.py @@ -153,12 +153,12 @@ def test_QFT(self): self.assertEqual(1, len(counts)) self.assertTrue("0000" in counts) - def test_single_qubit_QV(self): - """Test single qubit QuantumVolume""" - state = AerStatevector(QuantumVolume(1)) + def test_two_qubit_QV(self): + """Test two qubit QuantumVolume""" + state = AerStatevector(QuantumVolume(2)) counts = state.sample_counts(shots=1024) - self.assertEqual(1, len(counts)) - self.assertTrue("0" in counts) + self.assertEqual(4, len(counts)) + self.assertTrue("00" in counts) def test_evolve(self): """Test method and device properties"""