From e26970a678b4f32d30732bd90ae5cfaa039fa5d7 Mon Sep 17 00:00:00 2001 From: gadial Date: Tue, 10 Dec 2024 10:40:36 +0200 Subject: [PATCH] Fix for save_expval truncation (#2265) * Fix for save_expval truncation * Fixed a bug in pauli truncation and add relevant test * limit cuQuantum version * fix setup.py * add release note --------- Co-authored-by: U-AzureAD\JUNDOI --- .github/workflows/build.yml | 4 +-- .github/workflows/deploy.yml | 4 +-- .../notes/fix_gpu_build-acc09ca02f2d54ea.yaml | 6 +++++ ...ve_expval_truncation-2ea6b9224b22956e.yaml | 4 +++ setup.py | 4 +-- src/framework/circuit.hpp | 15 ++++++++--- .../aer_simulator/test_save_expval.py | 18 +++++++++++++ test/terra/primitives/test_estimator_v2.py | 27 +++++++++++++++++++ 8 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 releasenotes/notes/fix_gpu_build-acc09ca02f2d54ea.yaml create mode 100644 releasenotes/notes/fix_save_expval_truncation-2ea6b9224b22956e.yaml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 365904df88..98c08c8a5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,7 +77,7 @@ jobs: - name: Build wheels env: CIBW_BEFORE_ALL: "sed -i -e 's/^mirrorlist/#mirrorlist/' -e 's/^#baseurl/baseurl/' -e 's/mirror.centos.org/vault.centos.org/' /etc/yum.repos.d/*.repo && 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_BUILD : "pip cache purge && pip install nvidia-cuda-runtime-cu11 nvidia-cublas-cu11 nvidia-cusolver-cu11 nvidia-cusparse-cu11 'cuquantum-cu11<24.11.0'" CIBW_SKIP: "*-manylinux_i686 pp* cp36* cp37* cp38* cp39* cp310* cp311* *musllinux*" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu-cu11 QISKIT_AER_CUDA_MAJOR=11 CMAKE_VERBOSE_MAKEFILE=true AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc AER_CUDA_ARCH="7.0 7.2 7.5 8.0 8.6 8.7" AER_PYTHON_CUDA_ROOT=/opt/_internal AER_CIBUILD=true CIBW_REPAIR_WHEEL_COMMAND: 'auditwheel repair --exclude libcudart.so.11.0 --exclude libcustatevec.so.1 --exclude libcutensornet.so.2 --exclude libcutensor.so.1 --exclude libcutensorMg.so.1 --exclude libcusolver.so.11 --exclude libcusolverMg.so.11 --exclude libcusparse.so.11 --exclude libcublas.so.11 --exclude libcublasLt.so.11 -w {dest_dir} {wheel}' @@ -110,7 +110,7 @@ jobs: - name: Build wheels env: CIBW_BEFORE_ALL: "sed -i -e 's/^mirrorlist/#mirrorlist/' -e 's/^#baseurl/baseurl/' -e 's/mirror.centos.org/vault.centos.org/' /etc/yum.repos.d/*.repo && yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/12.5.1/local_installers/cuda-repo-rhel8-12-5-local-12.5.1_555.42.06-1.x86_64.rpm && rpm -i cuda-repo-rhel8-12-5-local-12.5.1_555.42.06-1.x86_64.rpm && yum clean all && yum -y install cuda-toolkit-12-5 && 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_BUILD : "pip cache purge && pip install nvidia-cuda-runtime-cu12 nvidia-nvjitlink-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 'cuquantum-cu12<24.11.0'" CIBW_SKIP: "*-manylinux_i686 pp* cp36* cp37* cp38* cp39* cp310* cp311* *musllinux*" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu QISKIT_AER_CUDA_MAJOR=12 CMAKE_VERBOSE_MAKEFILE=true AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc AER_CUDA_ARCH="7.0 7.2 7.5 8.0 8.6 8.7 8.9 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}' diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a0a971dd58..26d3667847 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -144,7 +144,7 @@ jobs: - name: Build wheels env: CIBW_BEFORE_ALL: "sed -i -e 's/^mirrorlist/#mirrorlist/' -e 's/^#baseurl/baseurl/' -e 's/mirror.centos.org/vault.centos.org/' /etc/yum.repos.d/*.repo && 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_BEFORE_BUILD : "pip install nvidia-cuda-runtime-cu11 nvidia-cublas-cu11 nvidia-cusolver-cu11 nvidia-cusparse-cu11 'cuquantum-cu11<24.11.0'" 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 @@ -188,7 +188,7 @@ jobs: - name: Build wheels env: CIBW_BEFORE_ALL: "sed -i -e 's/^mirrorlist/#mirrorlist/' -e 's/^#baseurl/baseurl/' -e 's/mirror.centos.org/vault.centos.org/' /etc/yum.repos.d/*.repo && yum install -y yum-utils wget && wget -q https://developer.download.nvidia.com/compute/cuda/12.5.1/local_installers/cuda-repo-rhel8-12-5-local-12.5.1_555.42.06-1.x86_64.rpm && rpm -i cuda-repo-rhel8-12-5-local-12.5.1_555.42.06-1.x86_64.rpm && yum clean all && yum -y install cuda-toolkit-12-5 && 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_BEFORE_BUILD : "pip install nvidia-cuda-runtime-cu12 nvidia-nvjitlink-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 'cuquantum-cu12<24.11.0" 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 diff --git a/releasenotes/notes/fix_gpu_build-acc09ca02f2d54ea.yaml b/releasenotes/notes/fix_gpu_build-acc09ca02f2d54ea.yaml new file mode 100644 index 0000000000..dde1e12d9d --- /dev/null +++ b/releasenotes/notes/fix_gpu_build-acc09ca02f2d54ea.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + This fix limit the version of cuQuantum temporary to solve link issue + of GLIBC version containing in the latest cuQuantum. + Make sure to unlimit the version when cuQuantum will be fixed diff --git a/releasenotes/notes/fix_save_expval_truncation-2ea6b9224b22956e.yaml b/releasenotes/notes/fix_save_expval_truncation-2ea6b9224b22956e.yaml new file mode 100644 index 0000000000..41b1a9c8e4 --- /dev/null +++ b/releasenotes/notes/fix_save_expval_truncation-2ea6b9224b22956e.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Fixes a small bug preventing the expval truncation mechanism from activating correctly. diff --git a/setup.py b/setup.py index 56025cca8a..ec523b4971 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ "nvidia-cublas-cu11>=11.11.3.6", "nvidia-cusolver-cu11>=11.4.1.48", "nvidia-cusparse-cu11>=11.7.5.86", - "cuquantum-cu11>=23.3.0", + "cuquantum-cu11>=23.3.0,<24.11.0", ] classifiers_cuda = [ "Environment :: GPU :: NVIDIA CUDA :: 11", @@ -68,7 +68,7 @@ "nvidia-cublas-cu12>=12.1.3.1", "nvidia-cusolver-cu12>=11.4.5.107", "nvidia-cusparse-cu12>=12.1.0.106", - "cuquantum-cu12>=23.3.0", + "cuquantum-cu12>=23.3.0,<24.11.0", ] classifiers_cuda = [ "Environment :: GPU :: NVIDIA CUDA :: 12", diff --git a/src/framework/circuit.hpp b/src/framework/circuit.hpp index eab35cd514..b37b5483a8 100644 --- a/src/framework/circuit.hpp +++ b/src/framework/circuit.hpp @@ -420,13 +420,14 @@ void Circuit::reset_metadata() { void Circuit::add_op_metadata(const Op &op) { has_conditional |= op.conditional; opset_.insert(op); - if (!qubitset_.empty() && - (op.type == OpType::save_expval || op.type == OpType::save_expval_var)) { + if (op.type == OpType::save_expval || op.type == OpType::save_expval_var) { for (int_t j = 0; j < op.expval_params.size(); j++) { const std::string &pauli = std::get<0>(op.expval_params[j]); for (int_t i = 0; i < op.qubits.size(); i++) { // add qubit with non-I operator - if (pauli[pauli.size() - 1 - i] != 'I') { + // we also add one qubit if the qubitset is empty to prevent edge cases + // with empty circuits + if (qubitset_.empty() || pauli[pauli.size() - 1 - i] != 'I') { qubitset_.insert(op.qubits[i]); } } @@ -682,6 +683,11 @@ void Circuit::set_params(bool truncation) { void Circuit::remap_qubits(Op &op) const { // truncate save_expval if (op.type == OpType::save_expval || op.type == OpType::save_expval_var) { + // map each qubit to its location in the pauli strings + std::unordered_map ops_pauli_qubit_map; + for (size_t i = 0; i < op.qubits.size(); ++i) { + ops_pauli_qubit_map[op.qubits[i]] = op.qubits.size() - 1 - i; + } int_t nparams = op.expval_params.size(); for (int_t i = 0; i < nparams; i++) { std::string &pauli = std::get<0>(op.expval_params[i]); @@ -689,10 +695,11 @@ void Circuit::remap_qubits(Op &op) const { new_pauli.resize(qubitmap_.size()); for (auto q = qubitmap_.cbegin(); q != qubitmap_.cend(); q++) { new_pauli[qubitmap_.size() - 1 - q->second] = - pauli[pauli.size() - 1 - q->first]; + pauli[ops_pauli_qubit_map[q->first]]; } pauli = new_pauli; } + op.qubits.resize(qubitmap_.size()); for (int_t i = 0; i < qubitmap_.size(); i++) { op.qubits[i] = i; } diff --git a/test/terra/backends/aer_simulator/test_save_expval.py b/test/terra/backends/aer_simulator/test_save_expval.py index 36131907f5..b602e16c76 100644 --- a/test/terra/backends/aer_simulator/test_save_expval.py +++ b/test/terra/backends/aer_simulator/test_save_expval.py @@ -271,3 +271,21 @@ def test_save_expval_var_stabilizer_pauli_cache_blocking(self, method, device, p blocking_qubits=2, max_parallel_threads=1, ) + + @supported_methods( + [ + "automatic", + "stabilizer", + "statevector", + "density_matrix", + "matrix_product_state", + "tensor_network", + ], + ) + def test_save_expval_truncation(self, method, device): + """Test save expval when qubits are not in use and are truncated""" + circ = QuantumCircuit(3) + circ.x(1) + oper = qi.Pauli("ZZ") + qubits = [1, 2] # qubit 0 will be truncated + self._test_save_expval(circ, oper, qubits, False, method=method, device=device) diff --git a/test/terra/primitives/test_estimator_v2.py b/test/terra/primitives/test_estimator_v2.py index 988d8dc743..8c08d013f1 100644 --- a/test/terra/primitives/test_estimator_v2.py +++ b/test/terra/primitives/test_estimator_v2.py @@ -445,6 +445,33 @@ def test_truncate(self): result_5[0].data["evs"][0], result_2[0].data["evs"][0], delta=self._rtol ) + def test_truncate_large_backends(self): + """Test truncation allows us to run few-qubit circuits on many-qubit backends""" + N = 12 + qc = QuantumCircuit(N) + + qc.x(range(N)) + qc.h(range(N)) + + for kk in range(N // 2, 0, -1): + qc.ch(kk, kk - 1) + for kk in range(N // 2, N - 1): + qc.ch(kk, kk + 1) + + op = SparsePauliOp("Z" * N) + backend_127 = GenericBackendV2(num_qubits=127) + pm = generate_preset_pass_manager(backend=backend_127, optimization_level=1) + isa_circuit = pm.run(qc) + mapped_observable = op.apply_layout(isa_circuit.layout) + + ref_est = StatevectorEstimator() + ref_result = ref_est.run(pubs=[(qc, op)]).result() + + est = EstimatorV2() + res = est.run(pubs=[(isa_circuit, mapped_observable)]).result() + + self.assertAlmostEqual(ref_result[0].data.evs, res[0].data.evs) + if __name__ == "__main__": unittest.main()