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"""