From 3e931d82f1a2ef180f8d7e16ca26d1685c12fbce Mon Sep 17 00:00:00 2001 From: Pradnya Khalate <148914294+khalatepradnya@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:06:23 -0800 Subject: [PATCH 01/26] [testing] Update passing tests (#2444) Multiple qubit and qvector allocations and measurements are supported on the `braket` target with changes from PR# 2416. Hence, two of the tests work without raising error(s) - mark them as such. Signed-off-by: Pradnya Khalate --- python/tests/backends/test_braket.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/python/tests/backends/test_braket.py b/python/tests/backends/test_braket.py index b05f564c40..b16ec705b4 100644 --- a/python/tests/backends/test_braket.py +++ b/python/tests/backends/test_braket.py @@ -51,10 +51,10 @@ def kernel(): mz(q0) mz(q1) - with pytest.raises(RuntimeError) as e: - cudaq.sample(kernel, shots_count=100) - assert "cannot declare a qubit register. Only 1 qubit register(s) is/are supported" in repr( - e) + counts = cudaq.sample(kernel, shots_count=100) + assert len(counts) == 2 + assert "00" in counts + assert "11" in counts def test_qvector_kernel(): @@ -129,10 +129,8 @@ def kernel(): h(ancilla) mz(ancilla) - with pytest.raises(RuntimeError) as e: - cudaq.sample(kernel, shots_count=100) - assert "cannot declare a qubit register. Only 1 qubit register(s) is/are supported" in repr( - e) + # Test here is that this runs + cudaq.sample(kernel, shots_count=100).dump() def test_control_modifier(): From f433d74e8e23a65fe5199062b7fdd7527c218740 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Tue, 3 Dec 2024 13:18:19 -0800 Subject: [PATCH 02/26] Build AWS SDK as part of the prerequisites (#2412) Signed-off-by: Bettina Heim --- .gitmodules | 3 - CMakeLists.txt | 67 +++++-------------- docker/build/devdeps.Dockerfile | 3 + docker/build/devdeps.manylinux.Dockerfile | 1 + pyproject.toml | 2 +- runtime/cudaq/platform/CMakeLists.txt | 4 +- .../platform/default/rest/CMakeLists.txt | 8 ++- .../default/rest/helpers/CMakeLists.txt | 4 +- scripts/configure_build.sh | 2 + scripts/install_prerequisites.sh | 36 ++++++++++ targettests/execution/angled_gate.cpp | 2 +- targettests/execution/bug_qubit.cpp | 2 +- targettests/execution/callable_kernel_arg.cpp | 2 +- targettests/execution/cudaq_observe.cpp | 2 +- .../execution/custom_operation_adj.cpp | 2 +- .../execution/custom_operation_basic.cpp | 2 +- targettests/execution/graph_coloring-1.cpp | 2 +- targettests/execution/graph_coloring.cpp | 2 +- targettests/execution/if_jit.cpp | 2 +- targettests/execution/int8_t.cpp | 2 +- targettests/execution/int8_t_free_func.cpp | 2 +- targettests/execution/load_value.cpp | 2 +- targettests/execution/state_preparation.cpp | 2 +- .../state_preparation_vector_sizes.cpp | 2 +- targettests/execution/swap_gate.cpp | 2 +- targettests/execution/variable_size_qreg.cpp | 2 +- targettests/lit.site.cfg.py.in | 7 ++ tpls/aws-sdk-cpp | 1 - 28 files changed, 96 insertions(+), 74 deletions(-) delete mode 160000 tpls/aws-sdk-cpp diff --git a/.gitmodules b/.gitmodules index 1eb1006f28..622993890c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -48,6 +48,3 @@ [submodule "tpls/Stim"] path = tpls/Stim url = https://github.com/quantumlib/Stim -[submodule "tpls/aws-sdk-cpp"] - path = tpls/aws-sdk-cpp - url = https://github.com/aws/aws-sdk-cpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e394c142..496447a8b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,11 @@ if (CUDAQ_ENABLE_REST AND NOT DEFINED CUDAQ_ENABLE_REMOTE_SIM) endif() endif() +# Enable AWS backends by default. +if (NOT DEFINED CUDAQ_ENABLE_BRAKET_BACKEND) + set(CUDAQ_ENABLE_BRAKET_BACKEND ON CACHE BOOL "Enable building AWS backends.") +endif() + # Generate a CompilationDatabase (compile_commands.json file) for our build, # for use by clang_complete, YouCompleteMe, etc. set(CMAKE_EXPORT_COMPILE_COMMANDS 1) @@ -136,6 +141,10 @@ option(CUDAQ_REQUIRE_OPENMP "Fail the build if OpenMP is not found." OFF) if(NOT LLVM_DIR AND EXISTS "$ENV{LLVM_INSTALL_PREFIX}/lib/cmake/llvm") SET(LLVM_DIR "$ENV{LLVM_INSTALL_PREFIX}/lib/cmake/llvm") endif() +if(NOT BLAS_LIBRARIES AND EXISTS "$ENV{BLAS_INSTALL_PREFIX}/libblas.a") + # CACHE INTERNAL is needed due to how FindBLAS.cmake works... + SET(BLAS_LIBRARIES "$ENV{BLAS_INSTALL_PREFIX}/libblas.a" CACHE INTERNAL "") +endif() if(NOT CUSTATEVEC_ROOT) SET(CUSTATEVEC_ROOT "$ENV{CUQUANTUM_INSTALL_PREFIX}") endif() @@ -151,9 +160,13 @@ endif() if(NOT OPENSSL_ROOT_DIR) SET(OPENSSL_ROOT_DIR "$ENV{OPENSSL_INSTALL_PREFIX}") endif() -if(NOT BLAS_LIBRARIES AND EXISTS "$ENV{BLAS_INSTALL_PREFIX}/libblas.a") - # CACHE INTERNAL is needed due to how FindBLAS.cmake works... - SET(BLAS_LIBRARIES "$ENV{BLAS_INSTALL_PREFIX}/libblas.a" CACHE INTERNAL "") +if (NOT crypto_LIBRARY AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/lib64/libcrypto.a") + SET(crypto_LIBRARY "$ENV{OPENSSL_INSTALL_PREFIX}/lib64/libcrypto.a" CACHE INTERNAL "") +elseif(NOT crypto_LIBRARY AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/lib/libcrypto.a") + SET(crypto_LIBRARY "$ENV{OPENSSL_INSTALL_PREFIX}/lib/libcrypto.a" CACHE INTERNAL "") +endif() +if (NOT crypto_INCLUDE_DIR AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/include") + SET(crypto_INCLUDE_DIR "$ENV{OPENSSL_INSTALL_PREFIX}/include" CACHE INTERNAL "") endif() if(NOT CURL_LIBRARY AND EXISTS "$ENV{CURL_INSTALL_PREFIX}/lib/libcurl.a") SET(CURL_LIBRARY "$ENV{CURL_INSTALL_PREFIX}/lib/libcurl.a") @@ -162,13 +175,8 @@ if(NOT CURL_LIBRARY AND EXISTS "$ENV{CURL_INSTALL_PREFIX}/lib/libcurl.a") SET(CMAKE_USE_SYSTEM_CURL TRUE) SET(CURL_NO_CURL_CMAKE ON) endif() -if (NOT crypto_LIBRARY AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/lib64/libcrypto.a") - SET(crypto_LIBRARY "$ENV{OPENSSL_INSTALL_PREFIX}/lib64/libcrypto.a" CACHE INTERNAL "") -elseif(NOT crypto_LIBRARY AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/lib/libcrypto.a") - SET(crypto_LIBRARY "$ENV{OPENSSL_INSTALL_PREFIX}/lib/libcrypto.a" CACHE INTERNAL "") -endif() -if (NOT crypto_INCLUDE_DIR AND EXISTS "$ENV{OPENSSL_INSTALL_PREFIX}/include") - SET(crypto_INCLUDE_DIR "$ENV{OPENSSL_INSTALL_PREFIX}/include" CACHE INTERNAL "") +if(NOT AWSSDK_ROOT AND CUDAQ_ENABLE_BRAKET_BACKEND) + SET(AWSSDK_ROOT "$ENV{AWS_INSTALL_PREFIX}") endif() if(NOT CUDAQ_EXTERNAL_NVQIR_SIMS) SET(CUDAQ_EXTERNAL_NVQIR_SIMS $ENV{CUDAQ_EXTERNAL_NVQIR_SIMS}) @@ -484,45 +492,6 @@ if (OPENSSL_FOUND AND CUDAQ_ENABLE_REST) # The asio submodule doesn't use cmake, so use find_path for it. find_path(ASIO_INCLUDE_DIR asio.hpp PATHS tpls/asio/asio/include) add_subdirectory(tpls/Crow) - # AWS SDK for C++ - set(SERVICE_COMPONENTS braket s3-crt sts) - # Call find_package without REQUIRED flag to see whether AWSSDK is installed. - find_package(AWSSDK COMPONENTS ${SERVICE_COMPONENTS}) - if (NOT AWSSDK_FOUND) - message(STATUS "AWS SDK not found. Building it.") - include(ProcessorCount) - ProcessorCount(N) - if(CMAKE_MAKE_PROGRAM MATCHES "make$") - set(MAKE_PARALLEL ${CMAKE_MAKE_PROGRAM} -j${N}) - else() - set(MAKE_PARALLEL ${CMAKE_MAKE_PROGRAM}) - endif() - execute_process(RESULT_VARIABLE result COMMAND cmake "-B${CMAKE_CURRENT_BINARY_DIR}/tpls/aws-sdk-cpp" "${CMAKE_CURRENT_SOURCE_DIR}/tpls/aws-sdk-cpp" - "-DAUTORUN_UNIT_TESTS=OFF" - "-DAWS_SDK_WARNINGS_ARE_ERRORS=OFF" - "-DAWS_USER_AGENT_CUSTOMIZATION=CUDA-Q/${CUDA_QUANTUM_VERSION}" - "-DBUILD_ONLY=braket;s3-crt;sts" - "-DBUILD_SHARED_LIBS=OFF" - "-DCMAKE_COMPILE_WARNING_AS_ERROR=OFF" - "-Dcrypto_LIBRARY=${crypto_LIBRARY}" - "-Dcrypto_INCLUDE_DIR=${crypto_INCLUDE_DIR}" - "-DCURL_LIBRARY=${CURL_LIBRARY}" - "-DCURL_INCLUDE_DIR=${CURL_INCLUDE_DIR}" - "-DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}" - "-DENABLE_TESTING=OFF" - "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" - "-G ${CMAKE_GENERATOR}" - ) - if(NOT ${result} STREQUAL "0") - message(FATAL_ERROR "Configuring aws-sdk-cpp failed.") - endif() - execute_process(RESULT_VARIABLE result COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR}/tpls/aws-sdk-cpp ${MAKE_PARALLEL} install) - if(NOT ${result} STREQUAL "0") - message(FATAL_ERROR "Building aws-sdk-cpp failed.") - endif() - endif() - # AWSSDK should be installed now. Call find_package with REQUIRED flag. - find_package(AWSSDK REQUIRED COMPONENTS ${SERVICE_COMPONENTS}) endif() # Check for CUDA Support diff --git a/docker/build/devdeps.Dockerfile b/docker/build/devdeps.Dockerfile index 200980c9bd..9be229826a 100644 --- a/docker/build/devdeps.Dockerfile +++ b/docker/build/devdeps.Dockerfile @@ -50,6 +50,7 @@ ENV BLAS_INSTALL_PREFIX=/usr/local/blas ENV ZLIB_INSTALL_PREFIX=/usr/local/zlib ENV OPENSSL_INSTALL_PREFIX=/usr/local/openssl ENV CURL_INSTALL_PREFIX=/usr/local/curl +ENV AWS_INSTALL_PREFIX=/usr/local/aws ## [Build Dependencies] RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -135,10 +136,12 @@ ENV BLAS_INSTALL_PREFIX=/usr/local/blas ENV ZLIB_INSTALL_PREFIX=/usr/local/zlib ENV OPENSSL_INSTALL_PREFIX=/usr/local/openssl ENV CURL_INSTALL_PREFIX=/usr/local/curl +ENV AWS_INSTALL_PREFIX=/usr/local/aws COPY --from=prereqs /usr/local/blas "$BLAS_INSTALL_PREFIX" COPY --from=prereqs /usr/local/zlib "$ZLIB_INSTALL_PREFIX" COPY --from=prereqs /usr/local/openssl "$OPENSSL_INSTALL_PREFIX" COPY --from=prereqs /usr/local/curl "$CURL_INSTALL_PREFIX" +COPY --from=prereqs /usr/local/aws "$AWS_INSTALL_PREFIX" # Install additional dependencies required to build and test CUDA-Q. RUN apt-get update && apt-get install --no-install-recommends -y wget ca-certificates \ diff --git a/docker/build/devdeps.manylinux.Dockerfile b/docker/build/devdeps.manylinux.Dockerfile index 7b134a3c5b..ed10b57faf 100644 --- a/docker/build/devdeps.manylinux.Dockerfile +++ b/docker/build/devdeps.manylinux.Dockerfile @@ -118,6 +118,7 @@ ENV BLAS_INSTALL_PREFIX=/usr/local/blas ENV ZLIB_INSTALL_PREFIX=/usr/local/zlib ENV OPENSSL_INSTALL_PREFIX=/usr/local/openssl ENV CURL_INSTALL_PREFIX=/usr/local/curl +ENV AWS_INSTALL_PREFIX=/usr/local/aws ENV CUQUANTUM_INSTALL_PREFIX=/usr/local/cuquantum ENV CUTENSOR_INSTALL_PREFIX=/usr/local/cutensor RUN bash /scripts/install_prerequisites.sh diff --git a/pyproject.toml b/pyproject.toml index d0d635b621..b5582ca4eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ wheel.packages = ["python/cudaq"] wheel.license-files = [ "LICENSE", "NOTICE", "CITATION.cff" ] build-dir = "_skbuild" metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" -cmake.minimum-version = "3.26" +cmake.minimum-version = "3.27" cmake.build-type = "Release" cmake.verbose = false cmake.args = [ diff --git a/runtime/cudaq/platform/CMakeLists.txt b/runtime/cudaq/platform/CMakeLists.txt index 4d2138e0a0..f6b8d51b9d 100644 --- a/runtime/cudaq/platform/CMakeLists.txt +++ b/runtime/cudaq/platform/CMakeLists.txt @@ -16,4 +16,6 @@ if (CUDAQ_ENABLE_REST) endif() add_subdirectory(fermioniq) -add_subdirectory(quera) \ No newline at end of file +if (AWSSDK_ROOT) + add_subdirectory(quera) +endif() \ No newline at end of file diff --git a/runtime/cudaq/platform/default/rest/CMakeLists.txt b/runtime/cudaq/platform/default/rest/CMakeLists.txt index d8389ca95c..7d636f302f 100644 --- a/runtime/cudaq/platform/default/rest/CMakeLists.txt +++ b/runtime/cudaq/platform/default/rest/CMakeLists.txt @@ -19,8 +19,12 @@ target_include_directories(cudaq-rest-qpu PRIVATE . $ $) -set(SERVICE_COMPONENTS braket s3-crt sts) -find_package(AWSSDK REQUIRED COMPONENTS ${SERVICE_COMPONENTS}) +if (AWSSDK_ROOT) + set(SERVICE_COMPONENTS braket s3-crt sts) + find_package(AWSSDK REQUIRED COMPONENTS ${SERVICE_COMPONENTS}) +else() + set(AWSSDK_LINK_LIBRARIES "") +endif() target_link_libraries(cudaq-rest-qpu PUBLIC diff --git a/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt b/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt index ad8b05c888..123434de52 100644 --- a/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt +++ b/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt @@ -6,8 +6,10 @@ # the terms of the Apache License 2.0 which accompanies this distribution. # # ============================================================================ # add_subdirectory(anyon) -add_subdirectory(braket) add_subdirectory(oqc) add_subdirectory(ionq) add_subdirectory(quantinuum) add_subdirectory(iqm) +if (AWSSDK_ROOT) + add_subdirectory(braket) +endif() diff --git a/scripts/configure_build.sh b/scripts/configure_build.sh index fc5d3b2462..aa8c087e71 100644 --- a/scripts/configure_build.sh +++ b/scripts/configure_build.sh @@ -19,6 +19,8 @@ export BLAS_INSTALL_PREFIX=/usr/local/blas export ZLIB_INSTALL_PREFIX=/usr/local/zlib export OPENSSL_INSTALL_PREFIX=/usr/local/openssl export CURL_INSTALL_PREFIX=/usr/local/curl +export AWS_INSTALL_PREFIX=/usr/local/aws + # [ /dev/null)" ]; then + aws_service_components='braket s3-crt sts' + git clone --filter=tree:0 https://github.com/aws/aws-sdk-cpp aws-sdk-cpp + cd aws-sdk-cpp && git checkout 1.11.454 && git submodule update --init --recursive + + # FIXME: CUDAQ VERSION? + mkdir build && cd build + cmake -G Ninja .. \ + -DCMAKE_INSTALL_PREFIX="${AWS_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=OFF \ + -DAWS_SDK_WARNINGS_ARE_ERRORS=OFF \ + -DAWS_USER_AGENT_CUSTOMIZATION=CUDA-Q/${CUDA_QUANTUM_VERSION} \ + -DBUILD_ONLY="$(echo $aws_service_components | tr ' ' ';')" \ + -DBUILD_SHARED_LIBS=OFF \ + -DZLIB_ROOT="${ZLIB_INSTALL_PREFIX}" \ + -DZLIB_USE_STATIC_LIBS=ON \ + -DOPENSSL_ROOT_DIR="${OPENSSL_INSTALL_PREFIX}" \ + -DCURL_LIBRARY="${CURL_INSTALL_PREFIX}/lib/libcurl.a" \ + -DCURL_INCLUDE_DIR="${CURL_INSTALL_PREFIX}/include" \ + -Dcrypto_LIBRARY="$(find "$OPENSSL_INSTALL_PREFIX" -name libcrypto.a)" \ + -Dcrypto_INCLUDE_DIR="${OPENSSL_INSTALL_PREFIX}/include" \ + -DENABLE_TESTING=OFF \ + -DAUTORUN_UNIT_TESTS=OFF + cmake --build . --config=Release + cmake --install . --config=Release + cd ../.. && rm -rf 1.11.454.tar.gz aws-sdk-cpp + remove_temp_installs + else + echo "AWS SDK already installed in $AWS_INSTALL_PREFIX." + fi +fi + # [cuQuantum and cuTensor] Needed for GPU-accelerated components cuda_driver=${CUDACXX:-${CUDA_HOME:-/usr/local/cuda}/bin/nvcc} cuda_version=`"$cuda_driver" --version 2>/dev/null | grep -o 'release [0-9]*\.[0-9]*' | cut -d ' ' -f 2` diff --git a/targettests/execution/angled_gate.cpp b/targettests/execution/angled_gate.cpp index cbafde6012..d3ac5c7e92 100644 --- a/targettests/execution/angled_gate.cpp +++ b/targettests/execution/angled_gate.cpp @@ -6,7 +6,7 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi #include diff --git a/targettests/execution/bug_qubit.cpp b/targettests/execution/bug_qubit.cpp index 02d64b5364..29ef77ad33 100644 --- a/targettests/execution/bug_qubit.cpp +++ b/targettests/execution/bug_qubit.cpp @@ -10,11 +10,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // RUN: cudaq-quake %cpp_std %s | cudaq-opt --promote-qubit-allocation | FileCheck --check-prefixes=MLIR %s diff --git a/targettests/execution/callable_kernel_arg.cpp b/targettests/execution/callable_kernel_arg.cpp index f6b91088f9..4842a253de 100644 --- a/targettests/execution/callable_kernel_arg.cpp +++ b/targettests/execution/callable_kernel_arg.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/execution/cudaq_observe.cpp b/targettests/execution/cudaq_observe.cpp index b3527ad319..edba980cab 100644 --- a/targettests/execution/cudaq_observe.cpp +++ b/targettests/execution/cudaq_observe.cpp @@ -8,13 +8,13 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies // RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ --target braket --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on #include diff --git a/targettests/execution/custom_operation_adj.cpp b/targettests/execution/custom_operation_adj.cpp index 314527fae5..3de4646cac 100644 --- a/targettests/execution/custom_operation_adj.cpp +++ b/targettests/execution/custom_operation_adj.cpp @@ -9,11 +9,11 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on #include diff --git a/targettests/execution/custom_operation_basic.cpp b/targettests/execution/custom_operation_basic.cpp index d567bd968a..05e6fbe15a 100644 --- a/targettests/execution/custom_operation_basic.cpp +++ b/targettests/execution/custom_operation_basic.cpp @@ -9,11 +9,11 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on #include diff --git a/targettests/execution/graph_coloring-1.cpp b/targettests/execution/graph_coloring-1.cpp index c669d054a4..baa89670c2 100644 --- a/targettests/execution/graph_coloring-1.cpp +++ b/targettests/execution/graph_coloring-1.cpp @@ -8,8 +8,8 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s // RUN: nvq++ %s -o %t --target quantinuum --emulate && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s; fi // clang-format on #include diff --git a/targettests/execution/graph_coloring.cpp b/targettests/execution/graph_coloring.cpp index 262743ad99..f6a98d7bc5 100644 --- a/targettests/execution/graph_coloring.cpp +++ b/targettests/execution/graph_coloring.cpp @@ -8,8 +8,8 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s // RUN: nvq++ %s -o %t --target quantinuum --emulate && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s; fi // clang-format on #include diff --git a/targettests/execution/if_jit.cpp b/targettests/execution/if_jit.cpp index 14a1f20d1d..b076a33ab2 100644 --- a/targettests/execution/if_jit.cpp +++ b/targettests/execution/if_jit.cpp @@ -10,11 +10,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/execution/int8_t.cpp b/targettests/execution/int8_t.cpp index 68a614bea1..38e0319bf5 100644 --- a/targettests/execution/int8_t.cpp +++ b/targettests/execution/int8_t.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/execution/int8_t_free_func.cpp b/targettests/execution/int8_t_free_func.cpp index a17bd83197..cec6a2439e 100644 --- a/targettests/execution/int8_t_free_func.cpp +++ b/targettests/execution/int8_t_free_func.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/execution/load_value.cpp b/targettests/execution/load_value.cpp index 39450fe054..2c453910ac 100644 --- a/targettests/execution/load_value.cpp +++ b/targettests/execution/load_value.cpp @@ -8,12 +8,12 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/execution/state_preparation.cpp b/targettests/execution/state_preparation.cpp index 5ee7a8671f..9eae1ae35f 100644 --- a/targettests/execution/state_preparation.cpp +++ b/targettests/execution/state_preparation.cpp @@ -10,13 +10,13 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi #include #include diff --git a/targettests/execution/state_preparation_vector_sizes.cpp b/targettests/execution/state_preparation_vector_sizes.cpp index 2c67e21d61..7fbc721415 100644 --- a/targettests/execution/state_preparation_vector_sizes.cpp +++ b/targettests/execution/state_preparation_vector_sizes.cpp @@ -10,13 +10,13 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi #include #include diff --git a/targettests/execution/swap_gate.cpp b/targettests/execution/swap_gate.cpp index 0d12f6fa16..2026f75ee2 100644 --- a/targettests/execution/swap_gate.cpp +++ b/targettests/execution/swap_gate.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include "cudaq.h" diff --git a/targettests/execution/variable_size_qreg.cpp b/targettests/execution/variable_size_qreg.cpp index fa46e6b06b..3d53fca0c2 100644 --- a/targettests/execution/variable_size_qreg.cpp +++ b/targettests/execution/variable_size_qreg.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on diff --git a/targettests/lit.site.cfg.py.in b/targettests/lit.site.cfg.py.in index 6dba2a0427..fd5ad765f5 100644 --- a/targettests/lit.site.cfg.py.in +++ b/targettests/lit.site.cfg.py.in @@ -43,6 +43,13 @@ config.test_remote_sim = "@CUDAQ_TEST_REMOTE_SIM@" if cmake_boolvar_to_bool(config.test_remote_sim): config.available_features.add('remote-sim') +config.cudaq_backends_braket = "@CUDAQ_ENABLE_BRAKET_BACKEND@" +if cmake_boolvar_to_bool(config.cudaq_backends_braket): + config.available_features.add('braket') + config.substitutions.append(('%braket_avail', 'true')) +else: + config.substitutions.append(('%braket_avail', 'false')) + import lit.llvm lit.llvm.initialize(lit_config, config) diff --git a/tpls/aws-sdk-cpp b/tpls/aws-sdk-cpp deleted file mode 160000 index a72c30acc3..0000000000 --- a/tpls/aws-sdk-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a72c30acc317b24d282640f0a40ef137acbeedec From f7a0b1280e271d8a2a8a749b5b585bc1782211dd Mon Sep 17 00:00:00 2001 From: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:47:33 +1100 Subject: [PATCH 03/26] Allow setting noise on measurement operation and apply it accordingly (#2447) Signed-off-by: Thien Nguyen --- runtime/common/NoiseModel.h | 2 +- runtime/nvqir/CircuitSimulator.h | 6 ++++ unittests/integration/noise_tester.cpp | 41 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/runtime/common/NoiseModel.h b/runtime/common/NoiseModel.h index fa7d3d4fd6..d52bc118b0 100644 --- a/runtime/common/NoiseModel.h +++ b/runtime/common/NoiseModel.h @@ -256,7 +256,7 @@ class noise_model { std::unordered_map gatePredicates; static constexpr const char *availableOps[] = { - "x", "y", "z", "h", "s", "t", "rx", "ry", "rz", "r1", "u3"}; + "x", "y", "z", "h", "s", "t", "rx", "ry", "rz", "r1", "u3", "mz"}; public: /// @brief default constructor diff --git a/runtime/nvqir/CircuitSimulator.h b/runtime/nvqir/CircuitSimulator.h index bb0d4cda74..f5ad4dae76 100644 --- a/runtime/nvqir/CircuitSimulator.h +++ b/runtime/nvqir/CircuitSimulator.h @@ -1315,6 +1315,12 @@ class CircuitSimulatorBase : public CircuitSimulator { // Flush the Gate Queue flushGateQueue(); + // Apply measurement noise (if any) + // Note: gate noises are applied during flushGateQueue + if (executionContext && executionContext->noiseModel) + applyNoiseChannel(/*gateName=*/"mz", /*controls=*/{}, + /*targets=*/{qubitIdx}, /*params=*/{}); + // If sampling, just store the bit, do nothing else. if (handleBasicSampling(qubitIdx, registerName)) return true; diff --git a/unittests/integration/noise_tester.cpp b/unittests/integration/noise_tester.cpp index 221a69d945..b3bd5934d2 100644 --- a/unittests/integration/noise_tester.cpp +++ b/unittests/integration/noise_tester.cpp @@ -641,3 +641,44 @@ CUDAQ_TEST(NoiseTest, checkCustomOperation) { } } #endif + +#if defined(CUDAQ_BACKEND_DM) || defined(CUDAQ_BACKEND_STIM) + +CUDAQ_TEST(NoiseTest, checkMeasurementNoise) { + cudaq::set_random_seed(13); + constexpr double bitFlipRate = 0.1; + cudaq::bit_flip_channel bf(bitFlipRate); + cudaq::noise_model noise; + // 10% bit flipping during measurement + noise.add_channel("mz", {0}, bf); + cudaq::set_noise(noise); + { + auto kernel = []() { + cudaq::qubit q; + x(q); + mz(q); + }; + auto counts = cudaq::sample(10000, kernel); + counts.dump(); + // Due to measurement errors, we have both 0/1 results. + EXPECT_EQ(2, counts.size()); + EXPECT_NEAR(counts.probability("0"), bitFlipRate, 0.01); + EXPECT_NEAR(counts.probability("1"), 1.0 - bitFlipRate, 0.01); + } + { + auto kernel = []() { + cudaq::qvector q(2); + x(q); + mz(q); + }; + auto counts = cudaq::sample(10000, kernel); + counts.dump(); + // We only have measurement noise on the first qubit. + EXPECT_EQ(2, counts.size()); + EXPECT_NEAR(counts.probability("01"), bitFlipRate, 0.01); + EXPECT_NEAR(counts.probability("11"), 1.0 - bitFlipRate, 0.01); + } + cudaq::unset_noise(); // clear for subsequent tests +} + +#endif From b8f44916433357e1bd39ba5ec3230f59f4f47a6f Mon Sep 17 00:00:00 2001 From: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:31:57 +1100 Subject: [PATCH 04/26] MGPU downstream updates (#2424) * [WIP] Build adjustments for new mgpu backends As the new libs will depend on runtime libcuda.so.1, we exclude it from the wheel packaging. Note: libcuda.so.1 comes with the NVIDIA driver (i.e., should be available on systems with GPU). Signed-off-by: Thien Nguyen * Update mgpu sha and fix spelling Signed-off-by: Thien Nguyen * Sort spelling_allowlist.txt Signed-off-by: Thien Nguyen --------- Signed-off-by: Thien Nguyen --- .github/workflows/config/gitlab_commits.txt | 2 +- .github/workflows/config/spelling_allowlist.txt | 1 + docker/build/assets.Dockerfile | 3 ++- docker/release/cudaq.wheel.Dockerfile | 3 ++- docs/sphinx/using/backends/simulators.rst | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/config/gitlab_commits.txt b/.github/workflows/config/gitlab_commits.txt index 07b9709655..16e13926a6 100644 --- a/.github/workflows/config/gitlab_commits.txt +++ b/.github/workflows/config/gitlab_commits.txt @@ -1,2 +1,2 @@ nvidia-mgpu-repo: cuda-quantum/cuquantum-mgpu.git -nvidia-mgpu-commit: 5ecebd6b7642e8526baf5930634f2f854aef9ea7 +nvidia-mgpu-commit: dadce3edc10564e94cd260590344d5840880087a diff --git a/.github/workflows/config/spelling_allowlist.txt b/.github/workflows/config/spelling_allowlist.txt index 5e60e19fb3..fdb4b0c5f1 100644 --- a/.github/workflows/config/spelling_allowlist.txt +++ b/.github/workflows/config/spelling_allowlist.txt @@ -45,6 +45,7 @@ Hadamards Hamiltonian Hamiltonians IQM +InfiniBand IonQ JIT JSON diff --git a/docker/build/assets.Dockerfile b/docker/build/assets.Dockerfile index 8b6acee43e..1d01ab62d3 100644 --- a/docker/build/assets.Dockerfile +++ b/docker/build/assets.Dockerfile @@ -230,7 +230,8 @@ RUN echo "Patching up wheel using auditwheel..." && \ --exclude libcustatevec.so.1 \ --exclude libcudart.so.11.0 \ --exclude libnvToolsExt.so.1 \ - --exclude libnvidia-ml.so.1 + --exclude libnvidia-ml.so.1 \ + --exclude libcuda.so.1 ## [ Date: Wed, 4 Dec 2024 19:08:27 -0800 Subject: [PATCH 05/26] Add support for logging matrices when running simulators (#2451) Signed-off-by: Ben Howe --- runtime/nvqir/CircuitSimulator.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/runtime/nvqir/CircuitSimulator.h b/runtime/nvqir/CircuitSimulator.h index f5ad4dae76..5b7c26dd7b 100644 --- a/runtime/nvqir/CircuitSimulator.h +++ b/runtime/nvqir/CircuitSimulator.h @@ -10,6 +10,7 @@ #include "Gates.h" #include "QIRTypes.h" +#include "common/Environment.h" #include "common/Logger.h" #include "common/MeasureCounts.h" #include "common/NoiseModel.h" @@ -725,6 +726,19 @@ class CircuitSimulatorBase : public CircuitSimulator { return; } + // Use static variables to reduce the number of calls to cudaq::getEnvBool + // since this is a frequently called piece of code, and we don't expect it + // to change in the middle of a run. + static bool z_env_var_checked = false; + static bool z_matrix_logging = false; + if (!z_env_var_checked) { + z_matrix_logging = cudaq::getEnvBool("CUDAQ_LOG_GATE_MATRIX", false); + z_env_var_checked = true; + } + if (z_matrix_logging) + cudaq::log("{}: matrix={}, controls={}, targets={}, params={}", name, + matrix, controls, targets, params); + gateQueue.emplace(name, matrix, controls, targets, params); } @@ -788,17 +802,7 @@ class CircuitSimulatorBase : public CircuitSimulator { /// The environment variable "CUDAQ_OBSERVE_FROM_SAMPLING" can be used to turn /// on or off this setting. bool shouldObserveFromSampling(bool defaultConfig = true) { - if (auto envVar = std::getenv(observeSamplingEnvVar); envVar) { - std::string asString = envVar; - std::transform(asString.begin(), asString.end(), asString.begin(), - [](auto c) { return std::tolower(c); }); - if (asString == "false" || asString == "off" || asString == "0") - return false; - if (asString == "true" || asString == "on" || asString == "1") - return true; - } - - return defaultConfig; + return cudaq::getEnvBool(observeSamplingEnvVar, defaultConfig); } bool isSinglePrecision() const override { From 5ccbcd24da7822afd6e102314b0c1731af030d0d Mon Sep 17 00:00:00 2001 From: Pradnya Khalate <148914294+khalatepradnya@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:13:09 -0800 Subject: [PATCH 06/26] [testing] Skip Python tests if dependency package missing (#2450) * Skip the 'test_evolve_dynamics_torch_integrators.py' tests if `torch` package not found. Signed-off-by: Pradnya Khalate --- .../integrators/test_evolve_dynamics_torch_integrators.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/tests/operator/integrators/test_evolve_dynamics_torch_integrators.py b/python/tests/operator/integrators/test_evolve_dynamics_torch_integrators.py index 9a2281de26..9c51965a94 100644 --- a/python/tests/operator/integrators/test_evolve_dynamics_torch_integrators.py +++ b/python/tests/operator/integrators/test_evolve_dynamics_torch_integrators.py @@ -7,6 +7,9 @@ # ============================================================================ # import pytest import cudaq + +torch = pytest.importorskip("torch") + # Note: the test model may create state, hence need to set the target to "dynamics" cudaq.set_target("dynamics") From 9d7e20a632b61f8ea4a103b06c3c75a8987d7de0 Mon Sep 17 00:00:00 2001 From: Pradnya Khalate <148914294+khalatepradnya@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:53:19 -0800 Subject: [PATCH 07/26] [docs] [testing] Follow-up for `braket` target and minor clean-up (#2448) * Update docs to show the `braket` examples * Remove the unsupported tests (tracked in issue#2325) * Emacs compatible banner * Update the C++ tests to reflect appropriate reason for skipping. (Note that `observe` API is not supported) --------- Signed-off-by: Pradnya Khalate --- CMakeLists.txt | 4 +- .../using/examples/hardware_providers.rst | 22 ++++- runtime/common/BraketExecutor.h | 23 ++--- runtime/common/BraketServerHelper.h | 2 +- targettests/braket/sudoku_2x2-1.cpp | 1 - targettests/braket/sudoku_2x2-bit_names.cpp | 1 - targettests/braket/sudoku_2x2-reg_name.cpp | 1 - targettests/braket/sudoku_2x2.cpp | 1 - unittests/backends/braket/BraketTester.cpp | 87 ++----------------- 9 files changed, 37 insertions(+), 105 deletions(-) delete mode 120000 targettests/braket/sudoku_2x2-1.cpp delete mode 120000 targettests/braket/sudoku_2x2-bit_names.cpp delete mode 120000 targettests/braket/sudoku_2x2-reg_name.cpp delete mode 120000 targettests/braket/sudoku_2x2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 496447a8b6..ebbbbd1654 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,9 +93,9 @@ if (CUDAQ_ENABLE_REST AND NOT DEFINED CUDAQ_ENABLE_REMOTE_SIM) endif() endif() -# Enable AWS backends by default. +# Enable Amazon Braket backends by default. if (NOT DEFINED CUDAQ_ENABLE_BRAKET_BACKEND) - set(CUDAQ_ENABLE_BRAKET_BACKEND ON CACHE BOOL "Enable building AWS backends.") + set(CUDAQ_ENABLE_BRAKET_BACKEND ON CACHE BOOL "Enable building AWS SDK for Amazon Braket backends.") endif() # Generate a CompilationDatabase (compile_commands.json file) for our build, diff --git a/docs/sphinx/using/examples/hardware_providers.rst b/docs/sphinx/using/examples/hardware_providers.rst index 076a4fed43..96fbc559f2 100644 --- a/docs/sphinx/using/examples/hardware_providers.rst +++ b/docs/sphinx/using/examples/hardware_providers.rst @@ -1,9 +1,25 @@ Using Quantum Hardware Providers ----------------------------------- -CUDA-Q contains support for using a set of hardware providers (IonQ, IQM, OQC, ORCA Computing and Quantinuum). -For more information about executing quantum kernels on different hardware backends, please take a look -at :doc:`hardware <../backends/hardware>`. +CUDA-Q contains support for using a set of hardware providers (Amazon Braket, +IonQ, IQM, OQC, ORCA Computing, Quantinuum and QuEra Computing). +For more information about executing quantum kernels on different hardware +backends, please take a look at :doc:`hardware <../backends/hardware>`. + +Amazon Braket +================================== + +The following code illustrates how to run kernels on Amazon Braket's backends. + +.. tab:: Python + + .. literalinclude:: ../../targets/python/braket.py + :language: python + +.. tab:: C++ + + .. literalinclude:: ../../targets/cpp/braket.cpp + :language: cpp IonQ ================================== diff --git a/runtime/common/BraketExecutor.h b/runtime/common/BraketExecutor.h index a3d432d5ad..05a13656d8 100644 --- a/runtime/common/BraketExecutor.h +++ b/runtime/common/BraketExecutor.h @@ -1,4 +1,4 @@ -/******************************************************************************* +/****************************************************************-*- C++ -*-**** * Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. * * All rights reserved. * * * @@ -7,27 +7,22 @@ ******************************************************************************/ #pragma once + +#include "common/BraketServerHelper.h" #include "common/Executor.h" #include "common/FmtCore.h" +#include "common/Logger.h" #include "common/MeasureCounts.h" #include "cudaq.h" - -#include -#include - -#include - #include -#include -#include - +#include #include #include #include - -#include "common/BraketServerHelper.h" -#include "common/Logger.h" - +#include +#include +#include +#include #include #include #include diff --git a/runtime/common/BraketServerHelper.h b/runtime/common/BraketServerHelper.h index 32f0d4695e..5f008f1a5b 100644 --- a/runtime/common/BraketServerHelper.h +++ b/runtime/common/BraketServerHelper.h @@ -1,4 +1,4 @@ -/******************************************************************************* +/****************************************************************-*- C++ -*-**** * Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. * * All rights reserved. * * * diff --git a/targettests/braket/sudoku_2x2-1.cpp b/targettests/braket/sudoku_2x2-1.cpp deleted file mode 120000 index 09aa81848d..0000000000 --- a/targettests/braket/sudoku_2x2-1.cpp +++ /dev/null @@ -1 +0,0 @@ -../execution/sudoku_2x2-1.cpp \ No newline at end of file diff --git a/targettests/braket/sudoku_2x2-bit_names.cpp b/targettests/braket/sudoku_2x2-bit_names.cpp deleted file mode 120000 index 15e2b47ae2..0000000000 --- a/targettests/braket/sudoku_2x2-bit_names.cpp +++ /dev/null @@ -1 +0,0 @@ -../execution/sudoku_2x2-bit_names.cpp \ No newline at end of file diff --git a/targettests/braket/sudoku_2x2-reg_name.cpp b/targettests/braket/sudoku_2x2-reg_name.cpp deleted file mode 120000 index 367a2098f4..0000000000 --- a/targettests/braket/sudoku_2x2-reg_name.cpp +++ /dev/null @@ -1 +0,0 @@ -../execution/sudoku_2x2-reg_name.cpp \ No newline at end of file diff --git a/targettests/braket/sudoku_2x2.cpp b/targettests/braket/sudoku_2x2.cpp deleted file mode 120000 index 23748412f1..0000000000 --- a/targettests/braket/sudoku_2x2.cpp +++ /dev/null @@ -1 +0,0 @@ -../execution/sudoku_2x2.cpp \ No newline at end of file diff --git a/unittests/backends/braket/BraketTester.cpp b/unittests/backends/braket/BraketTester.cpp index 89fea28164..b0d04753ae 100644 --- a/unittests/backends/braket/BraketTester.cpp +++ b/unittests/backends/braket/BraketTester.cpp @@ -25,8 +25,7 @@ bool isValidExpVal(double value) { } CUDAQ_TEST(BraketTester, checkSampleSync) { - GTEST_SKIP() << "Fails with: Please make sure all qubits in the qubit " - "register are used for tasks submitted to simulators"; + GTEST_SKIP() << "Amazon Braket credentials required"; std::string home = std::getenv("HOME"); std::string fileName = home + "/FakeCppBraket.config"; auto backendString = @@ -68,8 +67,7 @@ CUDAQ_TEST(BraketTester, checkSampleSyncEmulate) { } CUDAQ_TEST(BraketTester, checkSampleAsync) { - GTEST_SKIP() << "Fails with: Please make sure all qubits in the qubit " - "register are used for tasks submitted to simulators"; + GTEST_SKIP() << "Amazon Braket credentials required"; std::string home = std::getenv("HOME"); std::string fileName = home + "/FakeCppBraket.config"; auto backendString = fmt::format(fmt::runtime(backendStringTemplate), @@ -111,8 +109,8 @@ CUDAQ_TEST(BraketTester, checkSampleAsyncEmulate) { } CUDAQ_TEST(BraketTester, checkSampleAsyncLoadFromFile) { - GTEST_SKIP() << "Fails with: Please make sure all qubits in the qubit " - "register are used for tasks submitted to simulators"; + GTEST_SKIP() << "Fails with: Cannot persist a cudaq::future for a local " + "kernel execution."; std::string home = std::getenv("HOME"); std::string fileName = home + "/FakeCppBraket.config"; auto backendString = fmt::format(fmt::runtime(backendStringTemplate), @@ -148,9 +146,7 @@ CUDAQ_TEST(BraketTester, checkSampleAsyncLoadFromFile) { } CUDAQ_TEST(BraketTester, checkObserveSync) { - GTEST_SKIP() << "Fails with: Device requires all qubits in the program to be " - "measured. This may be caused by declaring non-contiguous " - "qubits or measuring partial qubits"; + GTEST_SKIP() << "Fails with: Cannot observe kernel with measures in it"; std::string home = std::getenv("HOME"); std::string fileName = home + "/FakeCppBraket.config"; auto backendString = fmt::format(fmt::runtime(backendStringTemplate), @@ -164,6 +160,7 @@ CUDAQ_TEST(BraketTester, checkObserveSync) { kernel.x(qubit[0]); kernel.ry(theta, qubit[1]); kernel.x(qubit[1], qubit[0]); + kernel.mz(qubit); using namespace cudaq::spin; cudaq::spin_op h = 5.907 - 2.1433 * x(0) * x(1) - 2.1433 * y(0) * y(1) + @@ -232,78 +229,6 @@ CUDAQ_TEST(BraketTester, checkObserveAsync) { EXPECT_TRUE(isValidExpVal(result.expectation())); } -CUDAQ_TEST(BraketTester, checkObserveAsyncEmulate) { - std::string home = std::getenv("HOME"); - std::string fileName = home + "/FakeCppBraket.config"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), - mockPort, fileName, machine); - backendString = - std::regex_replace(backendString, std::regex("false"), "true"); - - auto &platform = cudaq::get_platform(); - platform.setTargetBackend(backendString); - - auto [kernel, theta] = cudaq::make_kernel(); - auto qubit = kernel.qalloc(2); - kernel.x(qubit[0]); - kernel.ry(theta, qubit[1]); - kernel.x(qubit[1], qubit[0]); - - using namespace cudaq::spin; - cudaq::spin_op h = 5.907 - 2.1433 * x(0) * x(1) - 2.1433 * y(0) * y(1) + - .21829 * z(0) - 6.125 * z(1); - auto future = cudaq::observe_async(100000, 0, kernel, h, .59); - - auto result = future.get(); - result.dump(); - - printf("ENERGY: %lf\n", result.expectation()); - EXPECT_TRUE(isValidExpVal(result.expectation())); -} - -CUDAQ_TEST(BraketTester, checkObserveAsyncLoadFromFile) { - GTEST_SKIP() << "Fails with: Device requires all qubits in the program to be " - "measured. This may be caused by declaring non-contiguous " - "qubits or measuring partial qubits"; - std::string home = std::getenv("HOME"); - std::string fileName = home + "/FakeCppBraket.config"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), - mockPort, fileName, machine); - - auto &platform = cudaq::get_platform(); - platform.setTargetBackend(backendString); - - auto [kernel, theta] = cudaq::make_kernel(); - auto qubit = kernel.qalloc(2); - kernel.x(qubit[0]); - kernel.ry(theta, qubit[1]); - kernel.x(qubit[1], qubit[0]); - - using namespace cudaq::spin; - cudaq::spin_op h = 5.907 - 2.1433 * x(0) * x(1) - 2.1433 * y(0) * y(1) + - .21829 * z(0) - 6.125 * z(1); - auto future = cudaq::observe_async(kernel, h, .59); - - { - std::ofstream out("saveMeObserve.json"); - out << future; - } - - // Later you can come back and read it in - cudaq::async_result readIn(&h); - std::ifstream in("saveMeObserve.json"); - in >> readIn; - - // Get the results of the read in future. - auto result = readIn.get(); - - std::remove("saveMeObserve.json"); - result.dump(); - - printf("ENERGY: %lf\n", result.expectation()); - EXPECT_TRUE(isValidExpVal(result.expectation())); -} - int main(int argc, char **argv) { std::string home = std::getenv("HOME"); std::string fileName = home + "/FakeCppBraket.config"; From bee25dc0b7061387ea988d2563bf4e58492872c5 Mon Sep 17 00:00:00 2001 From: Ben Howe <141149032+bmhowe23@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:03:19 -0800 Subject: [PATCH 08/26] Update docs for stim target (#2449) * Update docs for stim target * Spelling * Slight rewording --------- Signed-off-by: Ben Howe --- .../workflows/config/spelling_allowlist.txt | 1 + docs/sphinx/using/backends/simulators.rst | 77 ++++++++++--------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/.github/workflows/config/spelling_allowlist.txt b/.github/workflows/config/spelling_allowlist.txt index fdb4b0c5f1..e74c23ba43 100644 --- a/.github/workflows/config/spelling_allowlist.txt +++ b/.github/workflows/config/spelling_allowlist.txt @@ -105,6 +105,7 @@ SLED SLES SLURM SVD +Stim Superpositions TBI TCP diff --git a/docs/sphinx/using/backends/simulators.rst b/docs/sphinx/using/backends/simulators.rst index e2457ff270..70a94343a5 100644 --- a/docs/sphinx/using/backends/simulators.rst +++ b/docs/sphinx/using/backends/simulators.rst @@ -300,41 +300,6 @@ use the following commands: nvq++ --target qpp-cpu program.cpp [...] -o program.x ./program.x - -Clifford-Only Simulation (CPU) -++++++++++++++++++++++++++++++++++ - -.. _stim-backend: - -This target provides a fast simulator for circuits containing *only* Clifford -gates. Any non-Clifford gates (such as T gates and Toffoli gates) are not -supported. This simulator is based on the `Stim `_ -library. - -To execute a program on the :code:`stim` target, use the following commands: - -.. tab:: Python - - .. code:: bash - - python3 program.py [...] --target stim - - The target can also be defined in the application code by calling - - .. code:: python - - cudaq.set_target('stim') - - If a target is set in the application code, this target will override the :code:`--target` command line flag given during program invocation. - -.. tab:: C++ - - .. code:: bash - - nvq++ --target stim program.cpp [...] -o program.x - ./program.x - - Tensor Network Simulators ================================== @@ -479,6 +444,48 @@ Specific aspects of the simulation can be configured by defining the following e The parallelism of Jacobi method (the default `CUDAQ_MPS_SVD_ALGO` setting) gives GPU better performance on small and medium size matrices. If you expect a large number of singular values (e.g., increasing the `CUDAQ_MPS_MAX_BOND` setting), please adjust the `CUDAQ_MPS_SVD_ALGO` setting accordingly. +Clifford-Only Simulator +================================== + +Stim (CPU) +++++++++++++++++++++++++++++++++++ + +.. _stim-backend: + +This target provides a fast simulator for circuits containing *only* Clifford +gates. Any non-Clifford gates (such as T gates and Toffoli gates) are not +supported. This simulator is based on the `Stim `_ +library. + +To execute a program on the :code:`stim` target, use the following commands: + +.. tab:: Python + + .. code:: bash + + python3 program.py [...] --target stim + + The target can also be defined in the application code by calling + + .. code:: python + + cudaq.set_target('stim') + + If a target is set in the application code, this target will override the :code:`--target` command line flag given during program invocation. + +.. tab:: C++ + + .. code:: bash + + nvq++ --target stim program.cpp [...] -o program.x + ./program.x + +.. note:: + CUDA-Q currently executes kernels using a "shot-by-shot" execution approach. + This allows for conditional gate execution (i.e. full control flow), but it + can be slower than executing Stim a single time and generating all the shots + from that single execution. + Fermioniq ================================== From b6d5339399d40d7b3c719b0e686759f93a9dcf91 Mon Sep 17 00:00:00 2001 From: Bruno Schmitt <7152025+boschmitt@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:40:37 +0100 Subject: [PATCH 09/26] [nvq++] Remove use of QTX. (#2439) RIP `qtx` dialect. Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> --- lib/Optimizer/Transforms/PassDetails.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Optimizer/Transforms/PassDetails.h b/lib/Optimizer/Transforms/PassDetails.h index 80d2331d0b..95d6b69476 100644 --- a/lib/Optimizer/Transforms/PassDetails.h +++ b/lib/Optimizer/Transforms/PassDetails.h @@ -19,10 +19,6 @@ #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassRegistry.h" -namespace qtx { -class CircuitOp; -} - namespace cudaq::opt { #define GEN_PASS_CLASSES From de0e7d63db81d8ba814d10a619fec649d860c5f1 Mon Sep 17 00:00:00 2001 From: Bruno Schmitt <7152025+boschmitt@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:13:30 +0100 Subject: [PATCH 10/26] [nvq++] Removes MLIR's `scf` dialect (#2435) We don't use this dialect and its presence is a historical artifact. This change triggered the removal of two tests: * `test/Quake/ghz.qke` * `test/Quake/iqft.qke` Both tests are a reminder of a past when we had to write quantum kernels directly in MLIR because of a lack of frontend. Both no longer test aything useful. The commit modifies `test/Quake/canonical-2.qke`, which was only testing the canonicalization of `cc.scope` operations. The new form is removes the clutter, making the test more precise. `test/Translate/ghz.qke` had to be modified because it uses MLIR's `affined.for` and its conversion to LLVMDialect requires `scf.for`. Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> Co-authored-by: Eric Schweitz --- include/cudaq/Optimizer/InitAllDialects.h | 2 - lib/Frontend/nvqpp/ConvertExpr.cpp | 1 - lib/Optimizer/CodeGen/CMakeLists.txt | 1 - lib/Optimizer/CodeGen/ConvertCCToLLVM.cpp | 2 - lib/Optimizer/CodeGen/ConvertToQIR.cpp | 2 - .../Transforms/ApplyOpSpecialization.cpp | 6 - test/Quake/canonical-2.qke | 65 +++------ test/Quake/ghz.qke | 45 ------ test/Quake/iqft.qke | 138 ------------------ test/Translate/ghz.qke | 77 +++++----- tools/cudaq-quake/CMakeLists.txt | 1 - 11 files changed, 64 insertions(+), 276 deletions(-) delete mode 100644 test/Quake/ghz.qke delete mode 100644 test/Quake/iqft.qke diff --git a/include/cudaq/Optimizer/InitAllDialects.h b/include/cudaq/Optimizer/InitAllDialects.h index fdb41114d5..c6df70d88f 100644 --- a/include/cudaq/Optimizer/InitAllDialects.h +++ b/include/cudaq/Optimizer/InitAllDialects.h @@ -18,7 +18,6 @@ #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" -#include "mlir/Dialect/SCF/IR/SCF.h" namespace cudaq { @@ -35,7 +34,6 @@ inline void registerAllDialects(mlir::DialectRegistry ®istry) { mlir::LLVM::LLVMDialect, mlir::math::MathDialect, mlir::memref::MemRefDialect, - mlir::scf::SCFDialect, // NVQ++ dialects cudaq::cc::CCDialect, diff --git a/lib/Frontend/nvqpp/ConvertExpr.cpp b/lib/Frontend/nvqpp/ConvertExpr.cpp index 8b1f2a2638..780fbe6acd 100644 --- a/lib/Frontend/nvqpp/ConvertExpr.cpp +++ b/lib/Frontend/nvqpp/ConvertExpr.cpp @@ -13,7 +13,6 @@ #include "cudaq/Optimizer/Dialect/CC/CCOps.h" #include "cudaq/Optimizer/Dialect/Quake/QuakeOps.h" #include "llvm/Support/Debug.h" -#include "mlir/Dialect/SCF/IR/SCF.h" #define DEBUG_TYPE "lower-ast-expr" diff --git a/lib/Optimizer/CodeGen/CMakeLists.txt b/lib/Optimizer/CodeGen/CMakeLists.txt index d555ce99a9..56951cd07a 100644 --- a/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/lib/Optimizer/CodeGen/CMakeLists.txt @@ -62,7 +62,6 @@ add_cudaq_library(OptCodeGen MLIRFuncToLLVM MLIRMathToFuncs MLIRMathToLLVM - MLIRSCFToControlFlow # Translation MLIRTargetLLVMIRExport diff --git a/lib/Optimizer/CodeGen/ConvertCCToLLVM.cpp b/lib/Optimizer/CodeGen/ConvertCCToLLVM.cpp index 3faa371156..7ad2618a4f 100644 --- a/lib/Optimizer/CodeGen/ConvertCCToLLVM.cpp +++ b/lib/Optimizer/CodeGen/ConvertCCToLLVM.cpp @@ -22,7 +22,6 @@ #include "mlir/Conversion/LLVMCommon/Pattern.h" #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" -#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Dialect/Arith/Transforms/Passes.h" #include "mlir/Target/LLVMIR/TypeToLLVM.h" @@ -121,7 +120,6 @@ struct CCToLLVM : public cudaq::opt::impl::CCToLLVMBase { arith::populateArithToLLVMConversionPatterns(ccTypeConverter, patterns); populateMathToLLVMConversionPatterns(ccTypeConverter, patterns); - populateSCFToControlFlowConversionPatterns(patterns); cf::populateControlFlowToLLVMConversionPatterns(ccTypeConverter, patterns); populateFuncToLLVMConversionPatterns(ccTypeConverter, patterns); cudaq::opt::populateCCToLLVMPatterns(ccTypeConverter, patterns); diff --git a/lib/Optimizer/CodeGen/ConvertToQIR.cpp b/lib/Optimizer/CodeGen/ConvertToQIR.cpp index c5b4606e2d..e23691af94 100644 --- a/lib/Optimizer/CodeGen/ConvertToQIR.cpp +++ b/lib/Optimizer/CodeGen/ConvertToQIR.cpp @@ -30,7 +30,6 @@ #include "mlir/Conversion/LLVMCommon/Pattern.h" #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" -#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Dialect/Arith/Transforms/Passes.h" #include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" @@ -172,7 +171,6 @@ class ConvertToQIR : public cudaq::opt::impl::ConvertToQIRBase { arith::populateArithToLLVMConversionPatterns(typeConverter, patterns); populateMathToLLVMConversionPatterns(typeConverter, patterns); - populateSCFToControlFlowConversionPatterns(patterns); cf::populateControlFlowToLLVMConversionPatterns(typeConverter, patterns); populateFuncToLLVMConversionPatterns(typeConverter, patterns); cudaq::opt::populateCCToLLVMPatterns(typeConverter, patterns); diff --git a/lib/Optimizer/Transforms/ApplyOpSpecialization.cpp b/lib/Optimizer/Transforms/ApplyOpSpecialization.cpp index c308206cef..b8a66f52c1 100644 --- a/lib/Optimizer/Transforms/ApplyOpSpecialization.cpp +++ b/lib/Optimizer/Transforms/ApplyOpSpecialization.cpp @@ -13,7 +13,6 @@ #include "cudaq/Optimizer/Transforms/Passes.h" #include "cudaq/Todo.h" #include "llvm/Support/Debug.h" -#include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/IR/Dominance.h" #include "mlir/IR/IRMapping.h" #include "mlir/Transforms/DialectConversion.h" @@ -558,11 +557,6 @@ class ApplySpecializationPass invert(newIfOp.getElseRegion()); continue; } - if (auto forOp = dyn_cast(op)) { - LLVM_DEBUG(llvm::dbgs() << "moving for: " << forOp << ".\n"); - TODO_loc(loc, "cannot make adjoint of kernel with scf.for"); - // should we convert to cc.loop and use code below? - } if (auto loopOp = dyn_cast(op)) { LLVM_DEBUG(llvm::dbgs() << "moving loop: " << loopOp << ".\n"); auto newLoopOp = cloneReversedLoop(builder, loopOp); diff --git a/test/Quake/canonical-2.qke b/test/Quake/canonical-2.qke index b37012ad7e..8dacf4c7f8 100644 --- a/test/Quake/canonical-2.qke +++ b/test/Quake/canonical-2.qke @@ -8,54 +8,29 @@ // RUN: cudaq-opt -canonicalize %s | FileCheck %s - func.func @__nvqpp__mlirgen__reflect_about_uniform(%arg0: !quake.veq) attributes {"cudaq-kernel"} { - %0 = quake.veq_size %arg0 : (!quake.veq) -> i64 - %c1_i32 = arith.constant 1 : i32 - %1 = arith.extsi %c1_i32 : i32 to i64 - %2 = arith.subi %0, %1 : i64 - %c0_i64 = arith.constant 0 : i64 - %c1_i64 = arith.constant 1 : i64 - %3 = arith.subi %2, %c1_i64 : i64 - %4 = quake.subveq %arg0, %c0_i64, %3 : (!quake.veq, i64, i64) -> !quake.veq - %5 = quake.veq_size %arg0 : (!quake.veq) -> i64 - %c1_i64_0 = arith.constant 1 : i64 - %6 = arith.subi %5, %c1_i64_0 : i64 - %7 = quake.extract_ref %arg0[%6] : (!quake.veq,i64) -> !quake.ref - %8 = cc.create_lambda { - cc.scope { - %c0 = arith.constant 0 : index - %c1 = arith.constant 1 : index - %10 = quake.veq_size %arg0 : (!quake.veq) -> i64 - %11 = arith.index_cast %10 : i64 to index - scf.for %arg1 = %c0 to %11 step %c1 { - %12 = quake.extract_ref %arg0[%arg1] : (!quake.veq,index) -> !quake.ref - quake.h %12 : (!quake.ref) -> () - } - } - } : !cc.callable<() -> ()> - %9 = cc.create_lambda { - cc.scope { - quake.z [%4] %7 : (!quake.veq, !quake.ref) -> () - } - } : !cc.callable<() -> ()> - quake.compute_action %8, %9 : !cc.callable<() -> ()>, !cc.callable<() -> ()> - return - } +func.func @canonicalize_scope(%arg0: !quake.ref) attributes {"cudaq-kernel"} { + %0 = cc.create_lambda { + cc.scope { + quake.h %arg0 : (!quake.ref) -> () + } + } : !cc.callable<() -> ()> + %1 = cc.create_lambda { + cc.scope { + quake.z %arg0 : (!quake.ref) -> () + } + } : !cc.callable<() -> ()> + quake.compute_action %0, %1 : !cc.callable<() -> ()>, !cc.callable<() -> ()> + return +} -// CHECK-LABEL: func.func @__nvqpp__mlirgen__reflect_about_uniform( -// CHECK: %[[VAL_12:.*]] = cc.create_lambda { +// CHECK-LABEL: func.func @canonicalize_scope( +// CHECK: %[[VAL_0:.*]] = cc.create_lambda { // CHECK-NOT: cc.scope -// CHECK: %[[VAL_13:.*]] = quake.veq_size %{{.*}} : (!quake.veq) -> i64 -// CHECK: %[[VAL_14:.*]] = arith.index_cast %[[VAL_13]] : i64 to index -// CHECK: scf.for %[[VAL_15:.*]] = %{{.*}} to %[[VAL_14]] step % -// CHECK: %[[VAL_16:.*]] = quake.extract_ref -// CHECK: quake.h %[[VAL_16]] -// CHECK: } +// CHECK: quake.h %{{.*}} : // CHECK: } : !cc.callable<() -> ()> -// CHECK: %[[VAL_17:.*]] = cc.create_lambda { +// CHECK: %[[VAL_1:.*]] = cc.create_lambda { // CHECK-NOT: cc.scope -// CHECK: quake.z [%{{.*}}] %{{.*}} : +// CHECK: quake.z %{{.*}} : // CHECK: } : !cc.callable<() -> ()> -// CHECK: quake.compute_action -// CHECK: return +// CHECK: quake.compute_action %[[VAL_0]], %[[VAL_1]] diff --git a/test/Quake/ghz.qke b/test/Quake/ghz.qke deleted file mode 100644 index ad6e662dea..0000000000 --- a/test/Quake/ghz.qke +++ /dev/null @@ -1,45 +0,0 @@ -// ========================================================================== // -// Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. // -// All rights reserved. // -// // -// This source code and the accompanying materials are made available under // -// the terms of the Apache License 2.0 which accompanies this distribution. // -// ========================================================================== // - -// RUN: cudaq-opt %s --canonicalize | FileCheck %s -module { - // CHECK: func.func @ghz(%[[arg0:.*]]: i32) { - // CHECK: %[[C1:.*]] = arith.constant 1 : i32 - // CHECK: %0 = quake.alloca !quake.veq[%[[arg0]] : i32] - // CHECK: %1 = quake.extract_ref %0[0] : (!quake.veq) -> !quake.ref - // CHECK: quake.h %1 : - // CHECK: %2 = arith.subi %arg0, %[[C1]] : i32 - // CHECK: %3 = arith.index_cast %2 : i32 to index - // CHECK: affine.for %arg1 = 0 to %3 { - // CHECK: %4 = arith.index_cast %arg1 : index to i32 - // CHECK: %5 = arith.addi %4, %[[C1]] : i32 - // CHECK: %6 = quake.extract_ref %0[%arg1] : (!quake.veq, index) -> !quake.ref - // CHECK: %7 = quake.extract_ref %0[%5] : (!quake.veq, i32) -> !quake.ref - // CHECK: quake.x [%6] %7 : (!quake.ref, !quake.ref) -> () - // CHECK: } - // CHECK: return - // CHECK: } - func.func @ghz(%arg0 : i32) { - // %size = arith.constant 3 : i32 - %c0 = arith.constant 0 : i32 - %one = arith.constant 1 : i32 - %q = quake.alloca !quake.veq[%arg0 : i32] - %q0 = quake.extract_ref %q[%c0] : (!quake.veq, i32) -> !quake.ref - quake.h %q0 : (!quake.ref) -> () - %size_m_1 = arith.subi %arg0, %one : i32 - %upper = arith.index_cast %size_m_1 : i32 to index - affine.for %i = 0 to %upper { - %i_int = arith.index_cast %i : index to i32 - %ip1 = arith.addi %i_int, %one : i32 - %qi = quake.extract_ref %q[%i] : (!quake.veq, index) -> !quake.ref - %qi1 = quake.extract_ref %q[%ip1] : (!quake.veq, i32) -> !quake.ref - quake.x [%qi] %qi1 : (!quake.ref, !quake.ref) -> () - } - return - } -} diff --git a/test/Quake/iqft.qke b/test/Quake/iqft.qke deleted file mode 100644 index 60adfbe545..0000000000 --- a/test/Quake/iqft.qke +++ /dev/null @@ -1,138 +0,0 @@ -// ========================================================================== // -// Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. // -// All rights reserved. // -// // -// This source code and the accompanying materials are made available under // -// the terms of the Apache License 2.0 which accompanies this distribution. // -// ========================================================================== // - -// CUDA-Q code -// struct iqft { -// void operator()(cudaq::qreg q) __qpu__ { -// int N = q.size(); -// // Swap qubits -// for (int i = 0; i < N / 2; ++i) { -// swap(q[i], q[N - i - 1]); -// } - -// for (int i = 0; i < N - 1; ++i) { -// h(q[i]); -// int j = i + 1; -// for (int y = i; y >= 0; --y) { // for (int y = -i; y < 1; y++) -// const double theta = -M_PI / std::pow(2.0, j - y); -// cphase(theta, q[j], q[y]); -// } -// } - -// h(q[N - 1]); -// } -// }; - -// RUN: cudaq-opt %s --canonicalize | FileCheck %s - -// CHECK: #map = affine_map<(d0) -> (-d0)> -// CHECK: module { -// CHECK: func.func @iqft(%arg0: !quake.veq) { -// CHECK: %[[CF0:.*]] = arith.constant 2.000000e+00 : f64 -// CHECK: %[[CF1:.*]] = arith.constant -3.1415926535897931 : f64 -// CHECK: %[[CI1:.*]] = arith.constant 1 : index -// CHECK: %[[CI0:.*]] = arith.constant 0 : index -// CHECK: %[[C1:.*]] = arith.constant 1 : i32 -// CHECK: %[[C2:.*]] = arith.constant 2 : i32 -// CHECK: %c-1_i32 = arith.constant -1 : i32 -// CHECK: %0 = quake.veq_size %arg0 : (!quake.veq) -> i64 -// CHECK: %1 = arith.trunci %0 : i64 to i32 -// CHECK: %2 = arith.subi %1, %[[C1]] : i32 -// CHECK: %3 = arith.index_cast %2 : i32 to index -// CHECK: %4 = arith.divsi %1, %[[C2]] : i32 -// CHECK: %5 = arith.index_cast %4 : i32 to index -// CHECK: scf.for %arg1 = %[[CI0]] to %5 step %[[CI1]] { -// CHECK: %7 = arith.index_cast %arg1 : index to i32 -// CHECK: %8 = arith.subi %1, %7 : i32 -// CHECK: %9 = arith.subi %8, %[[C1]] : i32 -// CHECK: %10 = quake.extract_ref %arg0[%7] : (!quake.veq, i32) -> !quake.ref -// CHECK: %11 = quake.extract_ref %arg0[%9] : (!quake.veq, i32) -> !quake.ref -// CHECK: quake.swap %10, %11 : (!quake.ref, !quake.ref) -> () -// CHECK: } -// CHECK: affine.for %arg1 = 0 to %3 { -// CHECK: %7 = arith.index_cast %arg1 : index to i32 -// CHECK: %8 = quake.extract_ref %arg0[%7] : (!quake.veq, i32) -> !quake.ref -// CHECK: quake.h %8 : (!quake.ref) -> () -// CHECK: %9 = arith.addi %7, %[[C1]] : i32 -// CHECK: affine.for %arg2 = #map(%arg1) to 1 { -// CHECK: %10 = arith.index_cast %arg2 : index to i32 -// CHECK: %11 = arith.muli %10, %c-1_i32 : i32 -// CHECK: %12 = arith.subi %9, %11 : i32 -// CHECK: %13 = arith.sitofp %12 : i32 to f64 -// CHECK: %14 = math.powf %[[CF0]], %13 : f64 -// CHECK: %15 = arith.divf %[[CF1]], %14 : f64 -// CHECK: %16 = quake.extract_ref %arg0[%9] : (!quake.veq, i32) -> !quake.ref -// CHECK: %17 = quake.extract_ref %arg0[%11] : (!quake.veq, i32) -> !quake.ref -// CHECK: quake.r1 (%15) [%16] %17 : (f64, !quake.ref, !quake.ref) -> () -// CHECK: } -// CHECK: } -// CHECK: %6 = quake.extract_ref %arg0[%2] : (!quake.veq, i32) -> !quake.ref -// CHECK: quake.h %6 : (!quake.ref) -> () -// CHECK: return -// CHECK: } -// CHECK: } - - -#lb = affine_map<(d0) -> (-1*d0)> - -module { - func.func @iqft(%arg0 : !quake.veq) { - %c1 = arith.constant 1 : i32 - %c0 = arith.constant 0 : i32 - %c2 = arith.constant 2 : i32 - %cn1 = arith.constant -1 : i32 - %nn = quake.veq_size %arg0 : (!quake.veq) -> i64 - %n = arith.trunci %nn : i64 to i32 - %nm1 = arith.subi %n, %c1 : i32 - %nm1idx = arith.index_cast %nm1 : i32 to index - %upper = arith.divsi %n, %c2 : i32 - %upper_cast = arith.index_cast %upper : i32 to index - %lower = arith.index_cast %c0 : i32 to index - %c1idx = arith.index_cast %c1 : i32 to index - - scf.for %arg2 = %lower to %upper_cast step %c1idx { - %7 = arith.index_cast %arg2 : index to i32 - %9 = arith.subi %n, %7 : i32 - %10 = arith.subi %9, %c1 : i32 - %qi = quake.extract_ref %arg0 [%7] : (!quake.veq,i32) -> !quake.ref - %qi1 = quake.extract_ref %arg0 [%10] : (!quake.veq,i32) -> !quake.ref - quake.swap %qi, %qi1 : (!quake.ref, !quake.ref) -> () - } - - affine.for %arg3 = 0 to %nm1idx { - %11 = arith.index_cast %arg3 : index to i32 - %qi = quake.extract_ref %arg0[%11] : (!quake.veq, i32) -> !quake.ref - quake.h %qi : (!quake.ref) -> () - %13 = arith.addi %11, %c1 : i32 - %12 = memref.alloca() : memref - memref.store %13, %12[] : memref - - %lb = arith.muli %11, %cn1 : i32 - %lbidx = arith.index_cast %lb : i32 to index - affine.for %arg4 = #lb(%arg3) to %c1idx { - %14 = arith.index_cast %arg4 : index to i32 - %15 = arith.muli %14, %cn1 : i32 - %cst = arith.constant 3.1415926535897931 : f64 - %cst_3 = arith.constant -1.000000e+00 : f64 - %16 = arith.mulf %cst_3, %cst : f64 - %c2f = arith.sitofp %c2 : i32 to f64 - %jmy = arith.subi %13, %15 : i32 - %s2f = arith.sitofp %jmy : i32 to f64 - %denom = math.powf %c2f, %s2f : f64 - %24 = arith.divf %16, %denom : f64 - %qj = quake.extract_ref %arg0[%13] : (!quake.veq, i32) -> !quake.ref - %qy = quake.extract_ref %arg0[%15] : (!quake.veq, i32) -> !quake.ref - quake.r1 (%24)[%qj] %qy : (f64,!quake.ref,!quake.ref) -> () - } - } - %qnm1 = quake.extract_ref %arg0[%nm1] : (!quake.veq,i32) -> !quake.ref - quake.h %qnm1 : (!quake.ref) -> () - return - } -} - diff --git a/test/Translate/ghz.qke b/test/Translate/ghz.qke index da78b2ec13..498750ae07 100644 --- a/test/Translate/ghz.qke +++ b/test/Translate/ghz.qke @@ -9,48 +9,59 @@ // RUN: cudaq-opt %s --canonicalize --add-dealloc | cudaq-translate --convert-to=qir | FileCheck %s module { // CHECK: %[[VAL_0:.*]] = zext i32 -// CHECK: %[[VAL_1:.*]] to i64 +// CHECK-SAME: %[[VAL_1:.*]] to i64 // CHECK: %[[VAL_2:.*]] = tail call %[[VAL_3:.*]]* @__quantum__rt__qubit_allocate_array(i64 %[[VAL_0]]) // CHECK: %[[VAL_4:.*]] = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%[[VAL_3]]* %[[VAL_2]], i64 0) // CHECK: %[[VAL_5:.*]] = bitcast i8* %[[VAL_4]] to %[[VAL_6:.*]]** // CHECK: %[[VAL_7:.*]] = load %[[VAL_6]]*, %[[VAL_6]]** %[[VAL_5]], align 8 // CHECK: tail call void @__quantum__qis__h(%[[VAL_6]]* %[[VAL_7]]) // CHECK: %[[VAL_8:.*]] = add i32 %[[VAL_1]], -1 -// CHECK: %[[VAL_9:.*]] = sext i32 %[[VAL_8]] to i64 -// CHECK: %[[VAL_10:.*]] = icmp sgt i32 %[[VAL_8]], 0 -// CHECK: br i1 %[[VAL_10]], label %[[VAL_11:.*]], label %[[VAL_12:[^,]*]] +// CHECK: %[[VAL_9:.*]] = icmp eq i32 %[[VAL_8]], 0 +// CHECK: br i1 %[[VAL_9]], label %[[VAL_10:.*]], label %[[VAL_11:.*]] +// CHECK: .lr.ph.preheader: +// CHECK-SAME: ; preds = %[[VAL_12:.*]] +// CHECK: %[[VAL_13:.*]] = zext i32 %[[VAL_8]] to i64 +// CHECK: br label %[[VAL_14:.*]] // CHECK: .lr.ph: -// CHECK-SAME: ; preds = %[[VAL_13:.*]], %[[VAL_11]] -// CHECK: %[[VAL_14:.*]] = phi i64 [ %[[VAL_15:.*]], %[[VAL_11]] ], [ 0, %[[VAL_13]] ] -// CHECK: %[[VAL_15]] = add nuw nsw i64 %[[VAL_14]], 1 -// CHECK: %[[VAL_16:.*]] = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%[[VAL_3]]* %[[VAL_2]], i64 %[[VAL_14]]) -// CHECK: %[[VAL_17:.*]] = bitcast i8* %[[VAL_16]] to %[[VAL_6]]** -// CHECK: %[[VAL_18:.*]] = load %[[VAL_6]]*, %[[VAL_6]]** %[[VAL_17]], align 8 -// CHECK: %[[VAL_19:.*]] = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%[[VAL_3]]* %[[VAL_2]], i64 %[[VAL_15]]) -// CHECK: %[[VAL_20:.*]] = bitcast i8* %[[VAL_19]] to %[[VAL_6]]** -// CHECK: %[[VAL_21:.*]] = load %[[VAL_6]]*, %[[VAL_6]]** %[[VAL_20]], align 8 -// CHECK: tail call void (i64, void (%Array*, %Qubit*)*, ...) @invokeWithControlQubits(i64 1, void (%Array*, %Qubit*)* nonnull @__quantum__qis__x__ctl, %Qubit* %[[VAL_18]], %Qubit* %[[VAL_21]]) -// CHECK: %[[VAL_22:.*]] = icmp eq i64 %[[VAL_15]], %[[VAL_9]] -// CHECK: br i1 %[[VAL_22]], label %[[VAL_12]], label %[[VAL_11]] +// CHECK-SAME: ; preds = %[[VAL_11]], %[[VAL_14]] +// CHECK: %[[VAL_15:.*]] = phi i64 [ 0, %[[VAL_11]] ], [ %[[VAL_16:.*]], %[[VAL_14]] ] +// CHECK: %[[VAL_17:.*]] = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%[[VAL_3]]* %[[VAL_2]], i64 %[[VAL_15]]) +// CHECK: %[[VAL_18:.*]] = bitcast i8* %[[VAL_17]] to %[[VAL_6]]** +// CHECK: %[[VAL_19:.*]] = load %[[VAL_6]]*, %[[VAL_6]]** %[[VAL_18]], align 8 +// CHECK: %[[VAL_16]] = add nuw nsw i64 %[[VAL_15]], 1 +// CHECK: %[[VAL_20:.*]] = tail call i8* @__quantum__rt__array_get_element_ptr_1d(%[[VAL_3]]* %[[VAL_2]], i64 %[[VAL_16]]) +// CHECK: %[[VAL_21:.*]] = bitcast i8* %[[VAL_20]] to %[[VAL_6]]** +// CHECK: %[[VAL_22:.*]] = load %[[VAL_6]]*, %[[VAL_6]]** %[[VAL_21]], align 8 +// CHECK: tail call void (i64, void (%[[VAL_3]]*, %[[VAL_6]]*)*, ...) @invokeWithControlQubits(i64 1, void (%[[VAL_3]]*, %[[VAL_6]]*)* nonnull @__quantum__qis__x__ctl, %[[VAL_6]]* %[[VAL_19]], %[[VAL_6]]* %[[VAL_22]]) +// CHECK: %[[VAL_23:.*]] = icmp eq i64 %[[VAL_16]], %[[VAL_13]] +// CHECK: br i1 %[[VAL_23]], label %[[VAL_10]], label %[[VAL_14]] // CHECK: ._crit_edge: -// CHECK-SAME: ; preds = %[[VAL_11]], %[[VAL_13]] +// CHECK-SAME: ; preds = %[[VAL_14]], %[[VAL_12]] // CHECK: tail call void @__quantum__rt__qubit_release_array(%[[VAL_3]]* %[[VAL_2]]) // CHECK: ret void - func.func @ghz(%arg0 : i32) { - %c0 = arith.constant 0 : i32 - %one = arith.constant 1 : i32 - %q = quake.alloca !quake.veq[%arg0 : i32] - %q0 = quake.extract_ref %q [%c0] : (!quake.veq,i32) -> !quake.ref - quake.h %q0 : (!quake.ref) -> () - %size_m_1 = arith.subi %arg0, %one : i32 - %upper = arith.index_cast %size_m_1 : i32 to index - affine.for %i = 0 to %upper { - %i_int = arith.index_cast %i : index to i32 - %ip1 = arith.addi %i_int, %one : i32 - %qi = quake.extract_ref %q [%i] : (!quake.veq,index) -> !quake.ref - %qi1 = quake.extract_ref %q [%ip1] : (!quake.veq,i32) -> !quake.ref - quake.x [%qi] %qi1 : (!quake.ref,!quake.ref) -> () - } - return + + func.func @ghz(%arg0: i32){ + %c1_i32 = arith.constant 1 : i32 + %c0_i32 = arith.constant 0 : i32 + %0 = quake.alloca !quake.veq[%arg0 : i32] + %1 = quake.extract_ref %0[0] : (!quake.veq) -> !quake.ref + quake.h %1 : (!quake.ref) -> () + %2 = cc.loop while ((%arg1 = %c0_i32) -> (i32)) { + %4 = arith.subi %arg0, %c1_i32 : i32 + %5 = arith.cmpi ult, %arg1, %4 : i32 + cc.condition %5(%arg1 : i32) + } do { + ^bb0(%arg1: i32): + %4 = quake.extract_ref %0[%arg1] : (!quake.veq, i32) -> !quake.ref + %5 = arith.addi %arg1, %c1_i32 : i32 + %6 = quake.extract_ref %0[%5] : (!quake.veq, i32) -> !quake.ref + quake.x [%4] %6 : (!quake.ref, !quake.ref) -> () + cc.continue %arg1 : i32 + } step { + ^bb0(%arg1: i32): + %3 = arith.addi %arg1, %c1_i32 : i32 + cc.continue %3 : i32 } + return + } } diff --git a/tools/cudaq-quake/CMakeLists.txt b/tools/cudaq-quake/CMakeLists.txt index 094378da76..f5f2960ed6 100644 --- a/tools/cudaq-quake/CMakeLists.txt +++ b/tools/cudaq-quake/CMakeLists.txt @@ -27,7 +27,6 @@ target_link_libraries(cudaq-quake MLIRAffineDialect MLIRMemRefDialect - MLIRSCFDialect clangCodeGen clangFrontendTool From e882fff31a4da716a9433ca834c2ed4c16183768 Mon Sep 17 00:00:00 2001 From: Bruno Schmitt <7152025+boschmitt@users.noreply.github.com> Date: Mon, 9 Dec 2024 23:37:25 +0100 Subject: [PATCH 11/26] [nvq++] Removes MLIR's `affine` dialect (#2436) * [nvq++] Removes MLIR's `scf` dialect We don't use this dialect and its presence is a historical artifact. This change triggered the removal of two tests: * `test/Quake/ghz.qke` * `test/Quake/iqft.qke` Both tests are a reminder of a past when we had to write quantum kernels directly in MLIR because of a lack of frontend. Both no longer test aything useful. The commit modifies `test/Quake/canonical-2.qke`, which was only testing the canonicalization of `cc.scope` operations. The new form is removes the clutter, making the test more precise. `test/Translate/ghz.qke` had to be modified because it uses MLIR's `affined.for` and its conversion to LLVMDialect requires `scf.for`. Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> * [nvq++] Remove MLIR's `affine` dialect. We don't use this dialect. The removal triggered the removel of one test: * `test/Quake/ccnot.qke` The test was not testing anything useful, only kernel inlining, which is already covered in other tests. Furthermore, the test is misleading because, contrary to what the kernel name might indicate, it is not implementing a `ccnot`. Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> --------- Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> Co-authored-by: Eric Schweitz --- include/cudaq/Frontend/nvqpp/ASTBridge.h | 1 - include/cudaq/Optimizer/InitAllDialects.h | 2 - include/cudaq/Optimizer/Transforms/Passes.h | 1 - lib/Optimizer/CodeGen/CMakeLists.txt | 1 - lib/Optimizer/CodeGen/ConvertToQIR.cpp | 2 - lib/Optimizer/Transforms/PassDetails.h | 1 - lib/Optimizer/Transforms/QuakeAddMetadata.cpp | 1 - runtime/cudaq/builder/kernel_builder.cpp | 2 - test/Quake/ccnot.qke | 52 ------------------- tools/cudaq-quake/CMakeLists.txt | 1 - 10 files changed, 64 deletions(-) delete mode 100644 test/Quake/ccnot.qke diff --git a/include/cudaq/Frontend/nvqpp/ASTBridge.h b/include/cudaq/Frontend/nvqpp/ASTBridge.h index baf4518fce..3b257dc51e 100644 --- a/include/cudaq/Frontend/nvqpp/ASTBridge.h +++ b/include/cudaq/Frontend/nvqpp/ASTBridge.h @@ -20,7 +20,6 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/ScopedHashTable.h" -#include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/Builders.h" diff --git a/include/cudaq/Optimizer/InitAllDialects.h b/include/cudaq/Optimizer/InitAllDialects.h index c6df70d88f..0748b5866a 100644 --- a/include/cudaq/Optimizer/InitAllDialects.h +++ b/include/cudaq/Optimizer/InitAllDialects.h @@ -10,7 +10,6 @@ #include "cudaq/Optimizer/Dialect/CC/CCDialect.h" #include "cudaq/Optimizer/Dialect/Quake/QuakeDialect.h" -#include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlow.h" @@ -26,7 +25,6 @@ inline void registerAllDialects(mlir::DialectRegistry ®istry) { // clang-format off registry.insert< // MLIR dialects - mlir::AffineDialect, mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, mlir::complex::ComplexDialect, diff --git a/include/cudaq/Optimizer/Transforms/Passes.h b/include/cudaq/Optimizer/Transforms/Passes.h index 77f461bec2..d699e25355 100644 --- a/include/cudaq/Optimizer/Transforms/Passes.h +++ b/include/cudaq/Optimizer/Transforms/Passes.h @@ -42,7 +42,6 @@ std::unique_ptr createQuakeSynthesizer(std::string_view, const void *, std::size_t startingArgIdx = 0, bool sameAddressSpace = false); -std::unique_ptr createRaiseToAffinePass(); std::unique_ptr createUnwindLoweringPass(); std::unique_ptr diff --git a/lib/Optimizer/CodeGen/CMakeLists.txt b/lib/Optimizer/CodeGen/CMakeLists.txt index 56951cd07a..5c056e0e11 100644 --- a/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/lib/Optimizer/CodeGen/CMakeLists.txt @@ -54,7 +54,6 @@ add_cudaq_library(OptCodeGen MLIRTransforms # Conversions - MLIRAffineToStandard MLIRArithToLLVM MLIRComplexToLibm MLIRComplexToLLVM diff --git a/lib/Optimizer/CodeGen/ConvertToQIR.cpp b/lib/Optimizer/CodeGen/ConvertToQIR.cpp index e23691af94..738ee66ea1 100644 --- a/lib/Optimizer/CodeGen/ConvertToQIR.cpp +++ b/lib/Optimizer/CodeGen/ConvertToQIR.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/FormatVariadic.h" -#include "mlir/Conversion/AffineToStandard/AffineToStandard.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" #include "mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h" #include "mlir/Conversion/ComplexToLibm/ComplexToLibm.h" @@ -166,7 +165,6 @@ class ConvertToQIR : public cudaq::opt::impl::ConvertToQIRBase { populateComplexToLibmConversionPatterns(patterns, 1); populateComplexToLLVMConversionPatterns(typeConverter, patterns); - populateAffineToStdConversionPatterns(patterns); arith::populateCeilFloorDivExpandOpsPatterns(patterns); arith::populateArithToLLVMConversionPatterns(typeConverter, patterns); populateMathToLLVMConversionPatterns(typeConverter, patterns); diff --git a/lib/Optimizer/Transforms/PassDetails.h b/lib/Optimizer/Transforms/PassDetails.h index 95d6b69476..36b45aa69e 100644 --- a/lib/Optimizer/Transforms/PassDetails.h +++ b/lib/Optimizer/Transforms/PassDetails.h @@ -11,7 +11,6 @@ #include "cudaq/Optimizer/Dialect/CC/CCDialect.h" #include "cudaq/Optimizer/Dialect/Quake/QuakeDialect.h" #include "cudaq/Optimizer/Dialect/Quake/QuakeOps.h" -#include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" diff --git a/lib/Optimizer/Transforms/QuakeAddMetadata.cpp b/lib/Optimizer/Transforms/QuakeAddMetadata.cpp index 6f174463f3..2c8dbc284b 100644 --- a/lib/Optimizer/Transforms/QuakeAddMetadata.cpp +++ b/lib/Optimizer/Transforms/QuakeAddMetadata.cpp @@ -12,7 +12,6 @@ #include "cudaq/Optimizer/Transforms/Passes.h" #include "cudaq/Todo.h" #include "llvm/Support/Debug.h" -#include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" diff --git a/runtime/cudaq/builder/kernel_builder.cpp b/runtime/cudaq/builder/kernel_builder.cpp index be415c6620..6870ebef2a 100644 --- a/runtime/cudaq/builder/kernel_builder.cpp +++ b/runtime/cudaq/builder/kernel_builder.cpp @@ -17,8 +17,6 @@ #include "cudaq/Optimizer/Dialect/Quake/QuakeDialect.h" #include "cudaq/Optimizer/Dialect/Quake/QuakeOps.h" #include "cudaq/Optimizer/Transforms/Passes.h" -#include "mlir/Dialect/Affine/IR/AffineOps.h" -#include "mlir/Dialect/Affine/Passes.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/ExecutionEngine/ExecutionEngine.h" diff --git a/test/Quake/ccnot.qke b/test/Quake/ccnot.qke deleted file mode 100644 index a74536dfd6..0000000000 --- a/test/Quake/ccnot.qke +++ /dev/null @@ -1,52 +0,0 @@ -// ========================================================================== // -// Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. // -// All rights reserved. // -// // -// This source code and the accompanying materials are made available under // -// the terms of the Apache License 2.0 which accompanies this distribution. // -// ========================================================================== // - -// RUN: cudaq-opt %s --inline --canonicalize | FileCheck %s - -module { - - // CHECK-LABEL: func.func @apply_x( - // CHECK-SAME: %[[arg0:.*]]: !quake.ref) { - // CHECK: quake.x %[[arg0]] : - // CHECK: return - // CHECK: } - - // CHECK-LABEL: func.func @ccnot() { - // CHECK: %[[a0:.*]] = quake.alloca !quake.veq<3> - // CHECK: affine.for %[[arg0:.*]] = 0 to 3 { - // CHECK: %[[a2:.*]] = quake.extract_ref %[[a0]][%[[arg0]]] : (!quake.veq<3>, index) -> !quake.ref - // CHECK: quake.x %[[a2]] : - // CHECK: } - // CHECK: %[[a1:.*]] = quake.extract_ref %[[a0]][1] : (!quake.veq<3>) -> !quake.ref - // CHECK: quake.x %[[a1]] : - // CHECK: return - // CHECK: } - - func.func @apply_x(%q : !quake.ref) { - quake.x %q : (!quake.ref) -> () - return - } - - func.func @ccnot() { - %c_3 = arith.constant 3 : i32 - %c_0 = arith.constant 0 : i32 - %c_1 = arith.constant 1 : i32 - %c_2 = arith.constant 2 : i32 - %qubits = quake.alloca !quake.veq [ %c_3 : i32 ] - %c_3_idx = arith.index_cast %c_3 : i32 to index - affine.for %i = 0 to %c_3_idx { - %q0 = quake.extract_ref %qubits [%i] : (!quake.veq, index) -> !quake.ref - quake.x %q0 : (!quake.ref) -> () - } - - %q1 = quake.extract_ref %qubits [%c_1] : (!quake.veq, i32) -> !quake.ref - func.call @apply_x(%q1) : (!quake.ref) -> () - - return - } -} diff --git a/tools/cudaq-quake/CMakeLists.txt b/tools/cudaq-quake/CMakeLists.txt index f5f2960ed6..277df39c22 100644 --- a/tools/cudaq-quake/CMakeLists.txt +++ b/tools/cudaq-quake/CMakeLists.txt @@ -25,7 +25,6 @@ target_link_libraries(cudaq-quake MLIRLLVMCommonConversion MLIRLLVMToLLVMIRTranslation - MLIRAffineDialect MLIRMemRefDialect clangCodeGen From aa760d7da5545fa5fd529a31cf110c7aae5ac603 Mon Sep 17 00:00:00 2001 From: Bruno Schmitt <7152025+boschmitt@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:47:11 +0100 Subject: [PATCH 12/26] [cmake] Remove unnecessary install commands. (#2440) In the case of the libraries, there is no need to install them twice. I opted to remove the install command that contains `EXPORT` because we don't use/install these export files, and so far they don't seem to be missed. (Even if we want to install these exports, the current way of doing this seems overly complicated, we can generate a single runtime export with everything that was built---something to be done on a later commit.) In the case of headers files: their installation is already covered by the installation of the `cudaq` directory and all `*.h` within. Signed-off-by: boschmitt <7152025+boschmitt@users.noreply.github.com> Co-authored-by: Eric Schweitz --- runtime/cudaq/algorithms/CMakeLists.txt | 3 +-- runtime/cudaq/algorithms/gradients/CMakeLists.txt | 11 ----------- .../algorithms/optimizers/ensmallen/CMakeLists.txt | 2 -- .../cudaq/algorithms/optimizers/nlopt/CMakeLists.txt | 2 -- runtime/cudaq/platform/default/CMakeLists.txt | 1 - runtime/cudaq/platform/default/rest/CMakeLists.txt | 1 - runtime/cudaq/platform/fermioniq/CMakeLists.txt | 3 +-- runtime/cudaq/platform/mqpu/CMakeLists.txt | 2 -- runtime/cudaq/platform/mqpu/remote/CMakeLists.txt | 1 - runtime/cudaq/platform/orca/CMakeLists.txt | 1 - runtime/cudaq/platform/quera/CMakeLists.txt | 1 - 11 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 runtime/cudaq/algorithms/gradients/CMakeLists.txt diff --git a/runtime/cudaq/algorithms/CMakeLists.txt b/runtime/cudaq/algorithms/CMakeLists.txt index 34c265dafb..2e7c67f536 100644 --- a/runtime/cudaq/algorithms/CMakeLists.txt +++ b/runtime/cudaq/algorithms/CMakeLists.txt @@ -6,5 +6,4 @@ # the terms of the Apache License 2.0 which accompanies this distribution. # # ============================================================================ # -add_subdirectory(gradients) -add_subdirectory(optimizers) \ No newline at end of file +add_subdirectory(optimizers) diff --git a/runtime/cudaq/algorithms/gradients/CMakeLists.txt b/runtime/cudaq/algorithms/gradients/CMakeLists.txt deleted file mode 100644 index 78a1174af1..0000000000 --- a/runtime/cudaq/algorithms/gradients/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# ============================================================================ # -# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # -# All rights reserved. # -# # -# This source code and the accompanying materials are made available under # -# the terms of the Apache License 2.0 which accompanies this distribution. # -# ============================================================================ # - -install (FILES central_difference.h DESTINATION include/cudaq/gradients/) -install (FILES parameter_shift.h DESTINATION include/cudaq/gradients/) -install (FILES forward_difference.h DESTINATION include/cudaq/gradients/) diff --git a/runtime/cudaq/algorithms/optimizers/ensmallen/CMakeLists.txt b/runtime/cudaq/algorithms/optimizers/ensmallen/CMakeLists.txt index a4107b2400..14b47bb316 100644 --- a/runtime/cudaq/algorithms/optimizers/ensmallen/CMakeLists.txt +++ b/runtime/cudaq/algorithms/optimizers/ensmallen/CMakeLists.txt @@ -38,8 +38,6 @@ if (NOT APPLE) target_link_options(${LIBRARY_NAME} PRIVATE -Wl,--exclude-libs,ALL) endif() -install (FILES ensmallen.h DESTINATION include/cudaq/algorithms/optimizers/) - install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-ensmallen-targets DESTINATION lib) install(EXPORT cudaq-ensmallen-targets FILE CUDAQEnsmallenTargets.cmake diff --git a/runtime/cudaq/algorithms/optimizers/nlopt/CMakeLists.txt b/runtime/cudaq/algorithms/optimizers/nlopt/CMakeLists.txt index e7490947ab..29fa224dca 100644 --- a/runtime/cudaq/algorithms/optimizers/nlopt/CMakeLists.txt +++ b/runtime/cudaq/algorithms/optimizers/nlopt/CMakeLists.txt @@ -16,8 +16,6 @@ target_include_directories(${LIBRARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/runtime) target_include_directories(${LIBRARY_NAME} SYSTEM PRIVATE nlopt-src/ nlopt-src/src/api) target_link_libraries(${LIBRARY_NAME} PRIVATE nlopt) -install (FILES nlopt.h DESTINATION include/cudaq/algorithms/optimizers/) - install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-nlopt-targets DESTINATION lib) install(EXPORT cudaq-nlopt-targets diff --git a/runtime/cudaq/platform/default/CMakeLists.txt b/runtime/cudaq/platform/default/CMakeLists.txt index 98bfd4be74..a4a65eaa18 100644 --- a/runtime/cudaq/platform/default/CMakeLists.txt +++ b/runtime/cudaq/platform/default/CMakeLists.txt @@ -29,7 +29,6 @@ target_link_libraries(${LIBRARY_NAME} PRIVATE fmt::fmt-header-only cudaq CUDAQTargetConfigUtil) -install(TARGETS ${LIBRARY_NAME} DESTINATION lib) install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-platform-default-targets DESTINATION lib) diff --git a/runtime/cudaq/platform/default/rest/CMakeLists.txt b/runtime/cudaq/platform/default/rest/CMakeLists.txt index 7d636f302f..7046be51de 100644 --- a/runtime/cudaq/platform/default/rest/CMakeLists.txt +++ b/runtime/cudaq/platform/default/rest/CMakeLists.txt @@ -40,4 +40,3 @@ target_link_libraries(cudaq-rest-qpu install(TARGETS cudaq-rest-qpu DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-rest-qpu-targets DESTINATION lib) diff --git a/runtime/cudaq/platform/fermioniq/CMakeLists.txt b/runtime/cudaq/platform/fermioniq/CMakeLists.txt index 74bc34ad54..1d667b404c 100644 --- a/runtime/cudaq/platform/fermioniq/CMakeLists.txt +++ b/runtime/cudaq/platform/fermioniq/CMakeLists.txt @@ -28,7 +28,6 @@ target_link_libraries(${LIBRARY_NAME} cudaq-platform-default) install(TARGETS ${LIBRARY_NAME} DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-fermioniq-qpu-targets DESTINATION lib) # install(EXPORT cudaq-fermioniq-qpu-targets # FILE CUDAQQPUFermioniqTargets.cmake @@ -37,4 +36,4 @@ install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-fermioniq-qpu-targets DESTINATION l add_target_config(fermioniq) -add_subdirectory(helpers) \ No newline at end of file +add_subdirectory(helpers) diff --git a/runtime/cudaq/platform/mqpu/CMakeLists.txt b/runtime/cudaq/platform/mqpu/CMakeLists.txt index ee1bfcbcac..5969d342b2 100644 --- a/runtime/cudaq/platform/mqpu/CMakeLists.txt +++ b/runtime/cudaq/platform/mqpu/CMakeLists.txt @@ -44,7 +44,5 @@ if (CUDA_FOUND AND CUSTATEVEC_ROOT) endif() install(TARGETS ${LIBRARY_NAME} DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} - EXPORT cudaq-platform-mqpu-targets DESTINATION lib) add_target_config(remote-mqpu) add_target_config(nvqc) diff --git a/runtime/cudaq/platform/mqpu/remote/CMakeLists.txt b/runtime/cudaq/platform/mqpu/remote/CMakeLists.txt index 1cdcc8ff5e..622b1d2388 100644 --- a/runtime/cudaq/platform/mqpu/remote/CMakeLists.txt +++ b/runtime/cudaq/platform/mqpu/remote/CMakeLists.txt @@ -18,4 +18,3 @@ target_link_libraries(cudaq-remote-simulator-qpu PUBLIC install(TARGETS cudaq-remote-simulator-qpu DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-remote-simulator-qpu-targets DESTINATION lib) diff --git a/runtime/cudaq/platform/orca/CMakeLists.txt b/runtime/cudaq/platform/orca/CMakeLists.txt index 3610b902a3..e8bd88e299 100644 --- a/runtime/cudaq/platform/orca/CMakeLists.txt +++ b/runtime/cudaq/platform/orca/CMakeLists.txt @@ -34,6 +34,5 @@ target_link_libraries(${LIBRARY_NAME} cudaq-platform-default) install(TARGETS ${LIBRARY_NAME} DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-orca-qpu-targets DESTINATION lib) add_target_config(orca) diff --git a/runtime/cudaq/platform/quera/CMakeLists.txt b/runtime/cudaq/platform/quera/CMakeLists.txt index 11e5b2f3e4..c59d72cab8 100644 --- a/runtime/cudaq/platform/quera/CMakeLists.txt +++ b/runtime/cudaq/platform/quera/CMakeLists.txt @@ -40,6 +40,5 @@ target_link_libraries(${LIBRARY_NAME} cudaq-platform-default) install(TARGETS ${LIBRARY_NAME} DESTINATION lib) -install(TARGETS ${LIBRARY_NAME} EXPORT cudaq-quera-qpu-targets DESTINATION lib) add_target_config(quera) From 95a4da75141a18220344e24db10d26712062ff75 Mon Sep 17 00:00:00 2001 From: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:01:01 +1100 Subject: [PATCH 13/26] Add number of trajectories to `observe_options` struct (#2456) * Add number of trajectories to observe option Signed-off-by: Thien Nguyen * Code format fix Signed-off-by: Thien Nguyen * Fix a compiler warning: we just need , no need to construct the whole observe_options Signed-off-by: Thien Nguyen * Update runtime/common/ExecutionContext.h Co-authored-by: Eric Schweitz Signed-off-by: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> * Update runtime/cudaq/algorithms/observe.h Co-authored-by: Eric Schweitz Signed-off-by: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> * Update runtime/cudaq/algorithms/observe.h Co-authored-by: Eric Schweitz Signed-off-by: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> * Code format fix Signed-off-by: Thien Nguyen --------- Signed-off-by: Thien Nguyen Signed-off-by: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> Co-authored-by: Eric Schweitz --- runtime/common/ExecutionContext.h | 4 ++++ runtime/cudaq/algorithms/observe.h | 20 ++++++++++++++++---- runtime/cudaq/algorithms/vqe.h | 3 +-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/runtime/common/ExecutionContext.h b/runtime/common/ExecutionContext.h index 933aa31b6e..8fca5fdee2 100644 --- a/runtime/common/ExecutionContext.h +++ b/runtime/common/ExecutionContext.h @@ -109,6 +109,10 @@ class ExecutionContext { /// `sample_result`. std::vector invocationResultBuffer; + /// @brief The number of trajectories to be used for an expectation + /// calculation on simulation backends that support trajectory simulation. + std::optional numberTrajectories; + /// @brief The Constructor, takes the name of the context /// @param n The name of the context ExecutionContext(const std::string n) : name(n) {} diff --git a/runtime/cudaq/algorithms/observe.h b/runtime/cudaq/algorithms/observe.h index 7b7254871e..6e5abe392b 100644 --- a/runtime/cudaq/algorithms/observe.h +++ b/runtime/cudaq/algorithms/observe.h @@ -60,9 +60,14 @@ concept ObserveCallValid = /// \p shots is the number of shots to run for the given kernel. The default of /// -1 means direct calculations for simulation backends. \p noise is the noise /// model to use for the observe operation. +/// \p num_trajectories is the optional number of trajectories to be used when +/// computing the expectation values in the presence of noise. This parameter is +/// only applied to simulation backends that support noisy +/// simulation of trajectories. struct observe_options { int shots = -1; cudaq::noise_model noise; + std::optional num_trajectories; }; namespace details { @@ -75,14 +80,17 @@ std::optional runObservation(KernelFunctor &&k, cudaq::spin_op &h, quantum_platform &platform, int shots, const std::string &kernelName, std::size_t qpu_id = 0, details::future *futureResult = nullptr, - std::size_t batchIteration = 0, - std::size_t totalBatchIters = 0) { + std::size_t batchIteration = 0, std::size_t totalBatchIters = 0, + std::optional numTrajectories = {}) { auto ctx = std::make_unique("observe", shots); ctx->kernelName = kernelName; ctx->spin = &h; if (shots > 0) ctx->shots = shots; + if (numTrajectories.has_value()) + ctx->numberTrajectories = *numTrajectories; + ctx->batchIteration = batchIteration; ctx->totalIterations = totalBatchIters; @@ -469,7 +477,10 @@ observe_result observe(const observe_options &options, QuantumKernel &&kernel, cudaq::invokeKernel(std::forward(kernel), std::forward(args)...); }, - H, platform, shots, kernelName) + H, platform, shots, kernelName, /*qpu_id=*/0, + /*futureResult=*/nullptr, + /*batchIteration=*/0, + /*totalBatchIters=*/0, options.num_trajectories) .value(); platform.reset_noise(); @@ -690,7 +701,8 @@ std::vector observe(cudaq::observe_options &options, [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, - H, platform, shots, kernelName, qpuId, nullptr, counter, N) + H, platform, shots, kernelName, qpuId, nullptr, counter, N, + options.num_trajectories) .value(); return ret; }; diff --git a/runtime/cudaq/algorithms/vqe.h b/runtime/cudaq/algorithms/vqe.h index 9df1f7b848..030a0b3e4e 100644 --- a/runtime/cudaq/algorithms/vqe.h +++ b/runtime/cudaq/algorithms/vqe.h @@ -185,8 +185,7 @@ optimization_result vqe(std::size_t shots, QuantumKernel &&kernel, return optimizer.optimize(n_params, [&](const std::vector &x, std::vector &grad_vec) { - observe_options options{static_cast(shots), cudaq::noise_model{}}; - double e = cudaq::observe(options, kernel, H, x, args...); + double e = cudaq::observe(shots, kernel, H, x, args...); return e; }); } From 917146db3594eaa844214523df2c593456688241 Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Tue, 10 Dec 2024 05:22:45 -0800 Subject: [PATCH 14/26] Fixes a bug with C++ argument handling in the front end. (#2459) This one particular path was not making sure the arguments were relaxed when they needed to be resulting in a type error. As a bonus, corrects the bernstein_vazirani example. Signed-off-by: Eric Schweitz --- docs/sphinx/applications/cpp/bernstein_vazirani.cpp | 2 +- lib/Frontend/nvqpp/ConvertExpr.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/applications/cpp/bernstein_vazirani.cpp b/docs/sphinx/applications/cpp/bernstein_vazirani.cpp index 5371d0d576..7ec7741eed 100644 --- a/docs/sphinx/applications/cpp/bernstein_vazirani.cpp +++ b/docs/sphinx/applications/cpp/bernstein_vazirani.cpp @@ -34,7 +34,7 @@ std::vector random_bits(int seed) { template struct oracle { - auto operator()(std::vector bitvector, cudaq::qview<> qs, + auto operator()(std::vector &bitvector, cudaq::qview<> qs, cudaq::qubit &aux) __qpu__ { for (size_t i = 0; i < nrOfBits; i++) { diff --git a/lib/Frontend/nvqpp/ConvertExpr.cpp b/lib/Frontend/nvqpp/ConvertExpr.cpp index 780fbe6acd..5de2e9cd2f 100644 --- a/lib/Frontend/nvqpp/ConvertExpr.cpp +++ b/lib/Frontend/nvqpp/ConvertExpr.cpp @@ -2310,8 +2310,10 @@ bool QuakeBridgeVisitor::VisitCXXOperatorCallExpr( // replace it with an indirect call to the func::ConstantOp. auto indirect = popValue(); auto funcTy = cast(indirect.getType()); + auto convertedArgs = + convertKernelArgs(builder, loc, 0, args, funcTy.getInputs()); auto call = builder.create( - loc, funcTy.getResults(), indirect, args); + loc, funcTy.getResults(), indirect, convertedArgs); if (call.getResults().empty()) return true; return pushValue(call.getResult(0)); From d87720e234504da3bc84d2152b61351027d8eeab Mon Sep 17 00:00:00 2001 From: Victory Omole Date: Tue, 10 Dec 2024 10:44:48 -0600 Subject: [PATCH 15/26] `Cudaq <> Superstaq` integration (#2423) * poc infleqtion server files Signed-off-by: Bharath * c++ existing tests links for server Signed-off-by: Bharath * add new directory Signed-off-by: Bharath * some debug prints in c++ tests Signed-off-by: Bharath * draft mock qpu sketch Signed-off-by: Bharath * add license header Signed-off-by: Bharath * Add infleqtion python test with mockserver * Ready to built testing wheel * Revert testIonQ * More reversions * DCO Remediation Commit for vtomole I, vtomole , hereby add my Signed-off-by to this commit: bc10bec9c9e36e009bf30cd4985badef449f1b53 I, vtomole , hereby add my Signed-off-by to this commit: 6f444ddfc9a3942a1c12b4a9fbb7f0a80342d308 I, vtomole , hereby add my Signed-off-by to this commit: 64463c1b1261a05cb22a988406b138a7728f8a96 I, vtomole , hereby add my Signed-off-by to this commit: ad36074592e0358af7c535fb3a3f8a61ecc911e2 Signed-off-by: vtomole * Run clang formatter Signed-off-by: vtomole * Format with yapf Signed-off-by: vtomole * Run yapf with Google style Signed-off-by: vtomole * add newline at end of some new files Signed-off-by: Bharath * remove debug bell test Signed-off-by: Bharath * Update infleqtion.yml Signed-off-by: vtomole * Fix a typo in cmake * Use unused port '62447' * Add the new sub-directory to cmake Signed-off-by: Pradnya Khalate * some review responses + updates Signed-off-by: Bharath * fix: commit format Signed-off-by: Bharath * Test for all gates, modifiers * Check observe call * Skip the `observe` tests on C++ since the mock server returns hard-coded values * Python `observe` test works but the expectation value may be out-of-range due to low number of shots * `cu3` is not (yet) supported * Updated C++ tests * Add state prep pass in lowering pipeline * Fix symbolic links Signed-off-by: Pradnya Khalate * update backend name Signed-off-by: Bharath * remove unused shots assignment Signed-off-by: Bharath * override polling seconds and error for canceled job Signed-off-by: Bharath * Additional tests for multiple qvectors and multiple measurements Signed-off-by: Pradnya Khalate --------- Signed-off-by: Bharath Signed-off-by: vtomole Signed-off-by: Pradnya Khalate Co-authored-by: Bharath Co-authored-by: Bharath Thotakura <113555655+bharat-thotakura@users.noreply.github.com> Co-authored-by: Pradnya Khalate --- lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp | 1 + .../Transforms/DecompositionPatterns.cpp | 35 ++ python/tests/backends/test_Infleqtion.py | 159 +++++++++ .../default/rest/helpers/CMakeLists.txt | 5 +- .../rest/helpers/infleqtion/CMakeLists.txt | 17 + .../infleqtion/InfleqtionServerHelper.cpp | 314 ++++++++++++++++++ .../rest/helpers/infleqtion/infleqtion.yml | 36 ++ targettests/execution/bug_qubit.cpp | 1 + targettests/execution/callable_kernel_arg.cpp | 1 + targettests/execution/cudaq_observe-cpp17.cpp | 1 + targettests/execution/cudaq_observe.cpp | 1 + .../execution/custom_operation_adj.cpp | 9 +- .../execution/custom_operation_basic.cpp | 9 +- .../execution/custom_operation_ctrl.cpp | 12 +- targettests/execution/graph_coloring-1.cpp | 1 + targettests/execution/graph_coloring.cpp | 1 + targettests/execution/if_jit.cpp | 1 + targettests/execution/int8_t.cpp | 1 + targettests/execution/int8_t_free_func.cpp | 1 + targettests/execution/load_value.cpp | 1 + targettests/execution/state_preparation.cpp | 1 + targettests/execution/sudoku_2x2-1.cpp | 1 + .../execution/sudoku_2x2-bit_names.cpp | 1 + targettests/execution/sudoku_2x2-reg_name.cpp | 1 + targettests/execution/sudoku_2x2.cpp | 1 + targettests/execution/swap_gate.cpp | 1 + targettests/execution/variable_size_qreg.cpp | 1 + targettests/infleqtion/bug_qubit.cpp | 1 + .../infleqtion/callable_kernel_arg.cpp | 1 + .../infleqtion/cudaq_observe-cpp17.cpp | 1 + targettests/infleqtion/cudaq_observe.cpp | 1 + .../infleqtion/custom_operation_adj.cpp | 1 + .../infleqtion/custom_operation_basic.cpp | 1 + targettests/infleqtion/graph_coloring-1.cpp | 1 + targettests/infleqtion/graph_coloring.cpp | 1 + targettests/infleqtion/if_jit.cpp | 1 + targettests/infleqtion/load_value.cpp | 1 + targettests/infleqtion/state_preparation.cpp | 1 + targettests/infleqtion/sudoku_2x2-1.cpp | 1 + .../infleqtion/sudoku_2x2-bit_names.cpp | 1 + .../infleqtion/sudoku_2x2-reg_name.cpp | 1 + targettests/infleqtion/sudoku_2x2.cpp | 1 + targettests/infleqtion/swap_gate.cpp | 1 + targettests/infleqtion/test-int8_t.cpp | 1 + .../infleqtion/test-int8_t_free_func.cpp | 1 + targettests/infleqtion/variable_size_qreg.cpp | 1 + targettests/lit.cfg.py | 2 +- unittests/backends/CMakeLists.txt | 1 + unittests/backends/infleqtion/CMakeLists.txt | 28 ++ .../InfleqtionStartServerAndTest.sh.in | 43 +++ .../backends/infleqtion/InfleqtionTester.cpp | 97 ++++++ utils/mock_qpu/__init__.py | 1 + utils/mock_qpu/infleqtion/__init__.py | 95 ++++++ 53 files changed, 884 insertions(+), 16 deletions(-) create mode 100644 python/tests/backends/test_Infleqtion.py create mode 100644 runtime/cudaq/platform/default/rest/helpers/infleqtion/CMakeLists.txt create mode 100644 runtime/cudaq/platform/default/rest/helpers/infleqtion/InfleqtionServerHelper.cpp create mode 100644 runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml create mode 120000 targettests/infleqtion/bug_qubit.cpp create mode 120000 targettests/infleqtion/callable_kernel_arg.cpp create mode 120000 targettests/infleqtion/cudaq_observe-cpp17.cpp create mode 120000 targettests/infleqtion/cudaq_observe.cpp create mode 120000 targettests/infleqtion/custom_operation_adj.cpp create mode 120000 targettests/infleqtion/custom_operation_basic.cpp create mode 120000 targettests/infleqtion/graph_coloring-1.cpp create mode 120000 targettests/infleqtion/graph_coloring.cpp create mode 120000 targettests/infleqtion/if_jit.cpp create mode 120000 targettests/infleqtion/load_value.cpp create mode 120000 targettests/infleqtion/state_preparation.cpp create mode 120000 targettests/infleqtion/sudoku_2x2-1.cpp create mode 120000 targettests/infleqtion/sudoku_2x2-bit_names.cpp create mode 120000 targettests/infleqtion/sudoku_2x2-reg_name.cpp create mode 120000 targettests/infleqtion/sudoku_2x2.cpp create mode 120000 targettests/infleqtion/swap_gate.cpp create mode 120000 targettests/infleqtion/test-int8_t.cpp create mode 120000 targettests/infleqtion/test-int8_t_free_func.cpp create mode 120000 targettests/infleqtion/variable_size_qreg.cpp create mode 100644 unittests/backends/infleqtion/CMakeLists.txt create mode 100644 unittests/backends/infleqtion/InfleqtionStartServerAndTest.sh.in create mode 100644 unittests/backends/infleqtion/InfleqtionTester.cpp create mode 100644 utils/mock_qpu/infleqtion/__init__.py diff --git a/lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp b/lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp index c5b98642c7..528492e6f8 100644 --- a/lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp +++ b/lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp @@ -41,6 +41,7 @@ static LogicalResult translateOperatorName(quake::OperatorInterface optor, .Case("ry", "cry") .Case("rz", "crz") .Case("swap", "cswap") + .Case("u3", "cu3") .Default(qkeName); } else if (optor.getControls().size() == 2) { name = StringSwitch(qkeName).Case("x", "ccx").Default(""); diff --git a/lib/Optimizer/Transforms/DecompositionPatterns.cpp b/lib/Optimizer/Transforms/DecompositionPatterns.cpp index b776c8461c..40680f6c2a 100644 --- a/lib/Optimizer/Transforms/DecompositionPatterns.cpp +++ b/lib/Optimizer/Transforms/DecompositionPatterns.cpp @@ -480,6 +480,40 @@ struct R1ToU3 : public OpRewritePattern { } }; +// quake.r1 (θ) target +// ───────────────────────────────── +// quake.r1(-θ) target +struct R1AdjToR1 : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + void initialize() { setDebugName("R1AdjToR1"); } + + LogicalResult matchAndRewrite(quake::R1Op op, + PatternRewriter &rewriter) const override { + if (!op.getControls().empty()) + return failure(); + if (!op.isAdj()) + return failure(); + + // Op info + Location loc = op->getLoc(); + Value target = op.getTarget(); + Value angle = op.getParameter(); + angle = rewriter.create(loc, angle); + + // Necessary/Helpful constants + SmallVector noControls; + SmallVector parameters = {angle}; + + QuakeOperatorCreator qRewriter(rewriter); + qRewriter.create(loc, parameters, noControls, target); + + qRewriter.selectWiresAndReplaceUses(op, target); + rewriter.eraseOp(op); + return success(); + } +}; + // quake.swap a, b // ─────────────────────────────────── // quake.cnot b, a; @@ -1575,6 +1609,7 @@ void cudaq::populateWithAllDecompositionPatterns(RewritePatternSet &patterns) { R1ToPhasedRx, R1ToRz, R1ToU3, + R1AdjToR1, // RxOp patterns CRxToCX, RxToPhasedRx, diff --git a/python/tests/backends/test_Infleqtion.py b/python/tests/backends/test_Infleqtion.py new file mode 100644 index 0000000000..24c4a11d24 --- /dev/null +++ b/python/tests/backends/test_Infleqtion.py @@ -0,0 +1,159 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +import cudaq, pytest, os +from cudaq import spin +import numpy as np + +## NOTE: Comment the following line which skips these tests in order to run in +# local dev environment after setting the API key +## NOTE: Superstaq costs apply +pytestmark = pytest.mark.skip("Infleqtion / Superstaq API key required") + + +@pytest.fixture(scope="session", autouse=True) +def do_something(): + cudaq.set_target("infleqtion") + yield "Running the tests." + cudaq.__clearKernelRegistries() + cudaq.reset_target() + + +def assert_close(got) -> bool: + return got < -1.5 and got > -1.9 + + +def test_simple_kernel(): + + @cudaq.kernel + def bell(): + qubits = cudaq.qvector(2) + h(qubits[0]) + x.ctrl(qubits[0], qubits[1]) + mz(qubits) + + counts = cudaq.sample(bell) + assert len(counts) == 2 + assert "00" in counts + assert "11" in counts + + +def test_all_gates(): + + @cudaq.kernel + def all_gates(): + q = cudaq.qubit() + h(q) + x(q) + y(q) + z(q) + r1(np.pi, q) + rx(np.pi, q) + ry(np.pi, q) + rz(np.pi, q) + s(q) + t(q) + u3(0.0, np.pi / 2, np.pi, q) + mz(q) + + qvec = cudaq.qvector(2) + x(qvec[0]) + swap(qvec[0], qvec[1]) + mz(qvec) + + ## control modifiers + qubits = cudaq.qvector(2) + h.ctrl(qubits[0], qubits[1]) + x.ctrl(qubits[1], qubits[0]) + y.ctrl(qubits[0], qubits[1]) + z.ctrl(qubits[1], qubits[0]) + r1.ctrl(np.pi / 2, qubits[0], qubits[1]) + rx.ctrl(np.pi / 4, qubits[1], qubits[0]) + ry.ctrl(np.pi / 8, qubits[0], qubits[1]) + rz.ctrl(np.pi, qubits[1], qubits[0]) + s.ctrl(qubits[0], qubits[1]) + t.ctrl(qubits[1], qubits[0]) + # u3.ctrl(0.0, np.pi / 2, np.pi, qubits[0], qubits[1]) + mz(qubits) + + qreg = cudaq.qvector(3) + x(qreg[0]) + x(qreg[1]) + swap.ctrl(qreg[0], qreg[1], qreg[2]) + mz(qreg) + + ## adjoint modifiers + r = cudaq.qubit() + r1.adj(np.pi, r) + rx.adj(np.pi / 2, r) + ry.adj(np.pi / 4, r) + rz.adj(np.pi / 8, r) + s.adj(r) + t.adj(r) + mz(r) + + # Test here is that this runs + cudaq.sample(all_gates).dump() + + +def test_multiple_qvector(): + + @cudaq.kernel + def kernel(): + qubits = cudaq.qvector(2) + ancilla = cudaq.qvector(2) + x(qubits) + h(ancilla) + mz(ancilla) + + # Test here is that this runs + cudaq.sample(kernel).dump() + + +def test_multiple_measure(): + + @cudaq.kernel + def kernel(): + q = cudaq.qvector(4) + a = cudaq.qvector(2) + h(q[0]) + cx(q[0], q[1]) + h(a) + cx(q[1], a[0]) + mz(q[1]) + mz(q[0]) + mz(a) + + # Test here is that this runs + cudaq.sample(kernel).dump() + + +def test_observe(): + cudaq.set_random_seed(13) + + @cudaq.kernel + def ansatz(theta: float): + qreg = cudaq.qvector(2) + x(qreg[0]) + ry(theta, qreg[1]) + x.ctrl(qreg[1], qreg[0]) + + # Define its spin Hamiltonian. + hamiltonian = 5.907 - 2.1433 * spin.x(0) * spin.x(1) - 2.1433 * spin.y( + 0) * spin.y(1) + .21829 * spin.z(0) - 6.125 * spin.z(1) + + res = cudaq.observe(ansatz, hamiltonian, .59, shots_count=2048) + ## Need to adjust expectation value range + # assert assert_close(res.expectation()) + print(res.expectation()) + + +# leave for gdb debugging +if __name__ == "__main__": + loc = os.path.abspath(__file__) + pytest.main([loc, "-s"]) diff --git a/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt b/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt index 123434de52..ff602ad246 100644 --- a/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt +++ b/runtime/cudaq/platform/default/rest/helpers/CMakeLists.txt @@ -6,10 +6,11 @@ # the terms of the Apache License 2.0 which accompanies this distribution. # # ============================================================================ # add_subdirectory(anyon) -add_subdirectory(oqc) +add_subdirectory(infleqtion) add_subdirectory(ionq) -add_subdirectory(quantinuum) add_subdirectory(iqm) +add_subdirectory(oqc) +add_subdirectory(quantinuum) if (AWSSDK_ROOT) add_subdirectory(braket) endif() diff --git a/runtime/cudaq/platform/default/rest/helpers/infleqtion/CMakeLists.txt b/runtime/cudaq/platform/default/rest/helpers/infleqtion/CMakeLists.txt new file mode 100644 index 0000000000..b4ef5e4bbc --- /dev/null +++ b/runtime/cudaq/platform/default/rest/helpers/infleqtion/CMakeLists.txt @@ -0,0 +1,17 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # +target_sources(cudaq-rest-qpu PRIVATE InfleqtionServerHelper.cpp) +add_target_config(infleqtion) + +add_library(cudaq-serverhelper-infleqtion SHARED InfleqtionServerHelper.cpp ) +target_link_libraries(cudaq-serverhelper-infleqtion + PUBLIC + cudaq-common + fmt::fmt-header-only +) +install(TARGETS cudaq-serverhelper-infleqtion DESTINATION lib) diff --git a/runtime/cudaq/platform/default/rest/helpers/infleqtion/InfleqtionServerHelper.cpp b/runtime/cudaq/platform/default/rest/helpers/infleqtion/InfleqtionServerHelper.cpp new file mode 100644 index 0000000000..7a157f6014 --- /dev/null +++ b/runtime/cudaq/platform/default/rest/helpers/infleqtion/InfleqtionServerHelper.cpp @@ -0,0 +1,314 @@ +/******************************************************************************* + * Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "common/Logger.h" +#include "common/RestClient.h" +#include "common/ServerHelper.h" +#include "cudaq/Support/Version.h" +#include "cudaq/utils/cudaq_utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +using json = nlohmann::json; + +bool isValidTarget(const std::string &input) { + static const std::unordered_set validTargets = { + "cq_sqale_qpu", "cq_sqale_simulator"}; + return validTargets.find(input) != validTargets.end(); +} + +std::string formatOpenQasm(const std::string &input_string) { + std::string escaped_string = + std::regex_replace(input_string, std::regex("\\\\"), "\\\\"); + escaped_string = std::regex_replace(escaped_string, std::regex("\""), "\\\""); + escaped_string = std::regex_replace(escaped_string, std::regex("\n"), "\\n"); + + std::ostringstream json_stream; + json_stream << "[\"" << escaped_string << "\"]"; + return json_stream.str(); +} + +namespace cudaq { + +/// @brief The InfleqtionServerHelper class extends the ServerHelper class to +/// handle interactions with the Infleqtion server for submitting and retrieving +/// quantum computation jobs. +class InfleqtionServerHelper : public ServerHelper { + static constexpr const char *DEFAULT_URL = "https://superstaq.infleqtion.com"; + static constexpr const char *DEFAULT_VERSION = "v0.2.0"; + +public: + /// @brief Returns the name of the server helper. + const std::string name() const override { return "infleqtion"; } + + /// @brief Returns the headers for the server requests. + RestHeaders getHeaders() override; + + /// @brief Initializes the server helper with the provided backend + /// configuration. + void initialize(BackendConfig config) override; + + /// @brief Creates a quantum computation job using the provided kernel + /// executions and returns the corresponding payload. + ServerJobPayload + createJob(std::vector &circuitCodes) override; + + /// @brief Extracts the job ID from the server's response to a job submission. + std::string extractJobId(ServerMessage &postResponse) override; + + /// @brief Constructs the URL for retrieving a job based on the server's + /// response to a job submission. + std::string constructGetJobPath(ServerMessage &postResponse) override; + + /// @brief Constructs the URL for retrieving a job based on a job ID. + std::string constructGetJobPath(std::string &jobId) override; + + /// @brief Checks if a job is done based on the server's response to a job + /// retrieval request. + bool jobIsDone(ServerMessage &getJobResponse) override; + + /// @brief Processes the server's response to a job retrieval request and + /// maps the results back to sample results. + cudaq::sample_result processResults(ServerMessage &getJobResponse, + std::string &jobId) override; + + /// @brief Override the polling interval method + std::chrono::microseconds + nextResultPollingInterval(ServerMessage &postResponse) override { + return std::chrono::seconds(1); + } + +private: + /// @brief RestClient used for HTTP requests. + RestClient client; + + /// @brief Helper method to retrieve the value of an environment variable. + std::string getEnvVar(const std::string &key, const std::string &defaultVal, + const bool isRequired) const; + + /// @brief Helper function to get value from config or return a default value. + std::string getValueOrDefault(const BackendConfig &config, + const std::string &key, + const std::string &defaultValue) const; + + /// @brief Helper method to check if a key exists in the configuration. + bool keyExists(const std::string &key) const; +}; + +// Initialize the Infleqtion server helper with a given backend configuration +void InfleqtionServerHelper::initialize(BackendConfig config) { + cudaq::info("Initializing Infleqtion Backend."); + + // Move the passed config into the member variable backendConfig + backendConfig = config; + + // Set default URL and version if not provided + backendConfig["url"] = getValueOrDefault(config, "url", DEFAULT_URL); + backendConfig["version"] = + getValueOrDefault(config, "version", DEFAULT_VERSION); + backendConfig["user_agent"] = getValueOrDefault( + config, "user_agent", "cudaq/" + std::string(cudaq::getVersion())); + backendConfig["machine"] = + getValueOrDefault(config, "machine", "cq_sqale_simulator"); + backendConfig["method"] = config["method"]; + + // Validate machine name client-side + if (!isValidTarget(backendConfig["machine"])) { + throw std::runtime_error("Invalid Infleqtion machine specified."); + } + + // Determine if token is required + bool isTokenRequired = [&]() { + auto it = config.find("emulate"); + return !(it != config.end() && it->second == "true"); + }(); + + // Get the API token from environment variable if not provided + if (!keyExists("token")) { + backendConfig["token"] = + getEnvVar("SUPERSTAQ_API_KEY", "0", isTokenRequired); + } + + // Construct the API job path + backendConfig["job_path"] = + backendConfig["url"] + '/' + backendConfig["version"] + "/jobs"; + + // Set shots if provided + if (config.find("shots") != config.end()) + this->setShots(std::stoul(config["shots"])); + + // Parse common parameters + parseConfigForCommonParams(config); +} + +// Get the headers for the API requests +RestHeaders InfleqtionServerHelper::getHeaders() { + // Check if the necessary keys exist in the configuration + if (!keyExists("token") || !keyExists("user_agent")) + throw std::runtime_error( + "Required keys 'token' or 'user_agent' not found in backendConfig."); + + // Construct the headers + RestHeaders headers; + headers["Authorization"] = backendConfig.at("token"); + headers["Content-Type"] = "application/json"; + headers["User-Agent"] = backendConfig.at("user_agent"); + + // Return the headers + return headers; +} + +// Create a job for the Infleqtion quantum computer +ServerJobPayload +InfleqtionServerHelper::createJob(std::vector &circuitCodes) { + // Check if the necessary keys exist in the configuration + if (!keyExists("machine") || !keyExists("job_path")) + throw std::runtime_error("Key doesn't exist in backendConfig."); + + auto &circuitCode = circuitCodes[0]; + + // Construct the job message + ServerMessage job; + job["qasm_strs"] = formatOpenQasm( + circuitCode.code); // Assuming code is in OpenQASM 2.0 format + job["target"] = backendConfig.at("machine"); + job["shots"] = shots; + + if (backendConfig.count("method")) + job["method"] = backendConfig.at("method"); + + // Store output names and reorder indices if necessary + OutputNamesType outputNamesMap; + for (auto &item : circuitCode.output_names.items()) { + std::size_t idx = std::stoul(item.key()); + ResultInfoType info; + info.qubitNum = idx; + info.registerName = item.value(); + outputNamesMap[idx] = info; + } + outputNames[circuitCode.name] = outputNamesMap; + reorderIdx[circuitCode.name] = circuitCode.mapping_reorder_idx; + + // Prepare headers + RestHeaders headers = getHeaders(); + + // Return a tuple containing the job path, headers, and the job message + auto ret = std::make_tuple(backendConfig.at("job_path"), headers, + std::vector{job}); + return ret; +} + +// Extract the job ID from the server's response +std::string InfleqtionServerHelper::extractJobId(ServerMessage &postResponse) { + // Check if the response contains 'job_ids' key + if (!postResponse.contains("job_ids") || !postResponse["job_ids"].is_array()) + throw std::runtime_error("ServerMessage doesn't contain 'job_ids' key."); + + // Extract job ID from list response + std::string jobId = postResponse["job_ids"][0]; + // Return the job ID + return jobId; +} + +// Construct the path to get a job based on the server's response +std::string +InfleqtionServerHelper::constructGetJobPath(ServerMessage &postResponse) { + // Extract job ID + std::string jobId = extractJobId(postResponse); + + // Construct the path + return constructGetJobPath(jobId); +} + +// Construct the path to get a job based on job ID +std::string InfleqtionServerHelper::constructGetJobPath(std::string &jobId) { + if (!keyExists("url") || !keyExists("version")) + throw std::runtime_error( + "Keys 'url' or 'version' don't exist in backendConfig."); + + // Construct the job path + std::string jobPath = backendConfig.at("url") + '/' + + backendConfig.at("version") + "/job/" + jobId; + return jobPath; +} + +// Check if a job is done +bool InfleqtionServerHelper::jobIsDone(ServerMessage &getJobResponse) { + // Check if the response contains 'status' key + if (!getJobResponse.contains("status")) + throw std::runtime_error("ServerMessage is missing job 'status' key."); + + std::string status = getJobResponse["status"]; + if (status == "Canceled") { + throw std::runtime_error("The submitted job was canceled."); + } + // Returns whether the job is done + return status == "Done"; +} + +// Process the results from a job +cudaq::sample_result +InfleqtionServerHelper::processResults(ServerMessage &getJobResponse, + std::string &jobId) { + // Check if the response contains 'samples' key + if (!getJobResponse.contains("samples")) + throw std::runtime_error("Samples not found in the job results."); + + // Extract samples + auto samplesJson = getJobResponse["samples"]; + cudaq::CountsDictionary counts; + for (auto &item : samplesJson.items()) { + std::string bitstring = item.key(); + std::size_t count = item.value(); + counts[bitstring] = count; + } + // Create an ExecutionResult + cudaq::ExecutionResult execResult{counts}; + + // Return the sample_result + return cudaq::sample_result{execResult}; +} + +// Helper method to retrieve an environment variable +std::string InfleqtionServerHelper::getEnvVar(const std::string &key, + const std::string &defaultVal, + const bool isRequired) const { + const char *env_var = std::getenv(key.c_str()); + if (env_var == nullptr) { + if (isRequired) + throw std::runtime_error("Environment variable " + key + + " is required but not set."); + else + return defaultVal; + } + return std::string(env_var); +} + +// Helper function to get a value from config or return a default +std::string InfleqtionServerHelper::getValueOrDefault( + const BackendConfig &config, const std::string &key, + const std::string &defaultValue) const { + auto it = config.find(key); + return (it != config.end()) ? it->second : defaultValue; +} + +// Check if a key exists in the backend configuration +bool InfleqtionServerHelper::keyExists(const std::string &key) const { + return backendConfig.find(key) != backendConfig.end(); +} + +} // namespace cudaq + +// Register the Infleqtion server helper in the CUDA-Q server helper factory +CUDAQ_REGISTER_TYPE(cudaq::ServerHelper, cudaq::InfleqtionServerHelper, + infleqtion) diff --git a/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml b/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml new file mode 100644 index 0000000000..5370880e27 --- /dev/null +++ b/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml @@ -0,0 +1,36 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +name: "infleqtion" +description: "CUDA-Q target for Infleqtion." + +config: + # Tell DefaultQuantumPlatform what QPU subtype to use + platform-qpu: remote_rest + # Add the rest-qpu library to the link list + link-libs: ["-lcudaq-rest-qpu"] + # Tell NVQ++ to generate glue code to set the target backend name + gen-target-backend: true + # Define the lowering pipeline + platform-lowering-config: "func.func(const-prop-complex,canonicalize,cse,lift-array-alloc),globalize-array-values,func.func(state-prep),unitary-synthesis,canonicalize,apply-op-specialization,aggressive-early-inlining,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(multicontrol-decomposition),decomposition{enable-patterns=SToR1,TToR1,SwapToCX,CCZToCX,CR1ToCX,CRyToCX,CRxToCX,R1AdjToR1,RxAdjToRx,RyAdjToRy,RzAdjToRz},func.func(memtoreg{quantum=0}),symbol-dce" + # Tell the rest-qpu that we are generating OpenQASM 2.0. + codegen-emission: qasm2 + # Library mode is only for simulators, physical backends must turn this off + library-mode: false + +target-arguments: + - key: machine + required: false + type: string + platform-arg: machine + help-string: "Specify the Infleqtion backend to run on." + - key: method + required: false + type: string + platform-arg: method + help-string: "Specify the circuit execution type, either: dry-run (ideal simulation) or noise-sim (noisy-simulation)." diff --git a/targettests/execution/bug_qubit.cpp b/targettests/execution/bug_qubit.cpp index 29ef77ad33..d33409b9c8 100644 --- a/targettests/execution/bug_qubit.cpp +++ b/targettests/execution/bug_qubit.cpp @@ -10,6 +10,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/callable_kernel_arg.cpp b/targettests/execution/callable_kernel_arg.cpp index 4842a253de..7ffa47ebc9 100644 --- a/targettests/execution/callable_kernel_arg.cpp +++ b/targettests/execution/callable_kernel_arg.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/cudaq_observe-cpp17.cpp b/targettests/execution/cudaq_observe-cpp17.cpp index b4fd29d195..c801560256 100644 --- a/targettests/execution/cudaq_observe-cpp17.cpp +++ b/targettests/execution/cudaq_observe-cpp17.cpp @@ -8,6 +8,7 @@ // REQUIRES: c++17 // clang-format off +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/cudaq_observe.cpp b/targettests/execution/cudaq_observe.cpp index edba980cab..4db6b8c644 100644 --- a/targettests/execution/cudaq_observe.cpp +++ b/targettests/execution/cudaq_observe.cpp @@ -8,6 +8,7 @@ // REQUIRES: c++20 // clang-format off +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies // RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/custom_operation_adj.cpp b/targettests/execution/custom_operation_adj.cpp index 3de4646cac..16dfefc218 100644 --- a/targettests/execution/custom_operation_adj.cpp +++ b/targettests/execution/custom_operation_adj.cpp @@ -8,11 +8,12 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/custom_operation_basic.cpp b/targettests/execution/custom_operation_basic.cpp index 05e6fbe15a..9ba007c8b7 100644 --- a/targettests/execution/custom_operation_basic.cpp +++ b/targettests/execution/custom_operation_basic.cpp @@ -8,11 +8,12 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if $braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/custom_operation_ctrl.cpp b/targettests/execution/custom_operation_ctrl.cpp index 5119cc5099..079ce19681 100644 --- a/targettests/execution/custom_operation_ctrl.cpp +++ b/targettests/execution/custom_operation_ctrl.cpp @@ -6,12 +6,14 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ +// clang-format off // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --emulate --iqm-machine Apollo %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// clang-format on #include diff --git a/targettests/execution/graph_coloring-1.cpp b/targettests/execution/graph_coloring-1.cpp index baa89670c2..3257c9a9d3 100644 --- a/targettests/execution/graph_coloring-1.cpp +++ b/targettests/execution/graph_coloring-1.cpp @@ -8,6 +8,7 @@ // REQUIRES: c++20 // clang-format off +// RUN: nvq++ %s -o %t --target infleqtion --emulate && %t | FileCheck %s // RUN: nvq++ %s -o %t --target quantinuum --emulate && %t | FileCheck %s // RUN: if $braket_avail; then nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/graph_coloring.cpp b/targettests/execution/graph_coloring.cpp index f6a98d7bc5..fd11d40f42 100644 --- a/targettests/execution/graph_coloring.cpp +++ b/targettests/execution/graph_coloring.cpp @@ -8,6 +8,7 @@ // REQUIRES: c++20 // clang-format off +// RUN: nvq++ %s -o %t --target infleqtion --emulate && %t | FileCheck %s // RUN: nvq++ %s -o %t --target quantinuum --emulate && %t | FileCheck %s // RUN: if $braket_avail; then nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/if_jit.cpp b/targettests/execution/if_jit.cpp index b076a33ab2..ee820f3cdb 100644 --- a/targettests/execution/if_jit.cpp +++ b/targettests/execution/if_jit.cpp @@ -10,6 +10,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/int8_t.cpp b/targettests/execution/int8_t.cpp index 38e0319bf5..2ff858d5eb 100644 --- a/targettests/execution/int8_t.cpp +++ b/targettests/execution/int8_t.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/int8_t_free_func.cpp b/targettests/execution/int8_t_free_func.cpp index cec6a2439e..5df3f81249 100644 --- a/targettests/execution/int8_t_free_func.cpp +++ b/targettests/execution/int8_t_free_func.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/load_value.cpp b/targettests/execution/load_value.cpp index 2c453910ac..f4296931d4 100644 --- a/targettests/execution/load_value.cpp +++ b/targettests/execution/load_value.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/state_preparation.cpp b/targettests/execution/state_preparation.cpp index 9eae1ae35f..c1e74889f1 100644 --- a/targettests/execution/state_preparation.cpp +++ b/targettests/execution/state_preparation.cpp @@ -10,6 +10,7 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies diff --git a/targettests/execution/sudoku_2x2-1.cpp b/targettests/execution/sudoku_2x2-1.cpp index da170e1316..339f6352a0 100644 --- a/targettests/execution/sudoku_2x2-1.cpp +++ b/targettests/execution/sudoku_2x2-1.cpp @@ -9,6 +9,7 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/sudoku_2x2-bit_names.cpp b/targettests/execution/sudoku_2x2-bit_names.cpp index 601815bc47..740265a964 100644 --- a/targettests/execution/sudoku_2x2-bit_names.cpp +++ b/targettests/execution/sudoku_2x2-bit_names.cpp @@ -9,6 +9,7 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/sudoku_2x2-reg_name.cpp b/targettests/execution/sudoku_2x2-reg_name.cpp index 113a44d540..ff29a69a26 100644 --- a/targettests/execution/sudoku_2x2-reg_name.cpp +++ b/targettests/execution/sudoku_2x2-reg_name.cpp @@ -9,6 +9,7 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/sudoku_2x2.cpp b/targettests/execution/sudoku_2x2.cpp index 962651af24..34a117d8e5 100644 --- a/targettests/execution/sudoku_2x2.cpp +++ b/targettests/execution/sudoku_2x2.cpp @@ -9,6 +9,7 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/swap_gate.cpp b/targettests/execution/swap_gate.cpp index 2026f75ee2..4cbab8facf 100644 --- a/targettests/execution/swap_gate.cpp +++ b/targettests/execution/swap_gate.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/variable_size_qreg.cpp b/targettests/execution/variable_size_qreg.cpp index 3d53fca0c2..dfabe16498 100644 --- a/targettests/execution/variable_size_qreg.cpp +++ b/targettests/execution/variable_size_qreg.cpp @@ -8,6 +8,7 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s diff --git a/targettests/infleqtion/bug_qubit.cpp b/targettests/infleqtion/bug_qubit.cpp new file mode 120000 index 0000000000..375dd9e56e --- /dev/null +++ b/targettests/infleqtion/bug_qubit.cpp @@ -0,0 +1 @@ +../execution/bug_qubit.cpp \ No newline at end of file diff --git a/targettests/infleqtion/callable_kernel_arg.cpp b/targettests/infleqtion/callable_kernel_arg.cpp new file mode 120000 index 0000000000..fe1ee7fe77 --- /dev/null +++ b/targettests/infleqtion/callable_kernel_arg.cpp @@ -0,0 +1 @@ +../execution/callable_kernel_arg.cpp \ No newline at end of file diff --git a/targettests/infleqtion/cudaq_observe-cpp17.cpp b/targettests/infleqtion/cudaq_observe-cpp17.cpp new file mode 120000 index 0000000000..f59c756d1d --- /dev/null +++ b/targettests/infleqtion/cudaq_observe-cpp17.cpp @@ -0,0 +1 @@ +../execution/cudaq_observe-cpp17.cpp \ No newline at end of file diff --git a/targettests/infleqtion/cudaq_observe.cpp b/targettests/infleqtion/cudaq_observe.cpp new file mode 120000 index 0000000000..df437da453 --- /dev/null +++ b/targettests/infleqtion/cudaq_observe.cpp @@ -0,0 +1 @@ +../execution/cudaq_observe.cpp \ No newline at end of file diff --git a/targettests/infleqtion/custom_operation_adj.cpp b/targettests/infleqtion/custom_operation_adj.cpp new file mode 120000 index 0000000000..fd31ccab34 --- /dev/null +++ b/targettests/infleqtion/custom_operation_adj.cpp @@ -0,0 +1 @@ +../execution/custom_operation_adj.cpp \ No newline at end of file diff --git a/targettests/infleqtion/custom_operation_basic.cpp b/targettests/infleqtion/custom_operation_basic.cpp new file mode 120000 index 0000000000..17b469fc6f --- /dev/null +++ b/targettests/infleqtion/custom_operation_basic.cpp @@ -0,0 +1 @@ +../execution/custom_operation_basic.cpp \ No newline at end of file diff --git a/targettests/infleqtion/graph_coloring-1.cpp b/targettests/infleqtion/graph_coloring-1.cpp new file mode 120000 index 0000000000..101c19fe2b --- /dev/null +++ b/targettests/infleqtion/graph_coloring-1.cpp @@ -0,0 +1 @@ +../execution/graph_coloring-1.cpp \ No newline at end of file diff --git a/targettests/infleqtion/graph_coloring.cpp b/targettests/infleqtion/graph_coloring.cpp new file mode 120000 index 0000000000..c9e81401b7 --- /dev/null +++ b/targettests/infleqtion/graph_coloring.cpp @@ -0,0 +1 @@ +../execution/graph_coloring.cpp \ No newline at end of file diff --git a/targettests/infleqtion/if_jit.cpp b/targettests/infleqtion/if_jit.cpp new file mode 120000 index 0000000000..74ef9c8ee5 --- /dev/null +++ b/targettests/infleqtion/if_jit.cpp @@ -0,0 +1 @@ +../execution/if_jit.cpp \ No newline at end of file diff --git a/targettests/infleqtion/load_value.cpp b/targettests/infleqtion/load_value.cpp new file mode 120000 index 0000000000..f4588e8c7b --- /dev/null +++ b/targettests/infleqtion/load_value.cpp @@ -0,0 +1 @@ +../execution/load_value.cpp \ No newline at end of file diff --git a/targettests/infleqtion/state_preparation.cpp b/targettests/infleqtion/state_preparation.cpp new file mode 120000 index 0000000000..6ca6038292 --- /dev/null +++ b/targettests/infleqtion/state_preparation.cpp @@ -0,0 +1 @@ +../execution/state_preparation.cpp \ No newline at end of file diff --git a/targettests/infleqtion/sudoku_2x2-1.cpp b/targettests/infleqtion/sudoku_2x2-1.cpp new file mode 120000 index 0000000000..09aa81848d --- /dev/null +++ b/targettests/infleqtion/sudoku_2x2-1.cpp @@ -0,0 +1 @@ +../execution/sudoku_2x2-1.cpp \ No newline at end of file diff --git a/targettests/infleqtion/sudoku_2x2-bit_names.cpp b/targettests/infleqtion/sudoku_2x2-bit_names.cpp new file mode 120000 index 0000000000..15e2b47ae2 --- /dev/null +++ b/targettests/infleqtion/sudoku_2x2-bit_names.cpp @@ -0,0 +1 @@ +../execution/sudoku_2x2-bit_names.cpp \ No newline at end of file diff --git a/targettests/infleqtion/sudoku_2x2-reg_name.cpp b/targettests/infleqtion/sudoku_2x2-reg_name.cpp new file mode 120000 index 0000000000..367a2098f4 --- /dev/null +++ b/targettests/infleqtion/sudoku_2x2-reg_name.cpp @@ -0,0 +1 @@ +../execution/sudoku_2x2-reg_name.cpp \ No newline at end of file diff --git a/targettests/infleqtion/sudoku_2x2.cpp b/targettests/infleqtion/sudoku_2x2.cpp new file mode 120000 index 0000000000..23748412f1 --- /dev/null +++ b/targettests/infleqtion/sudoku_2x2.cpp @@ -0,0 +1 @@ +../execution/sudoku_2x2.cpp \ No newline at end of file diff --git a/targettests/infleqtion/swap_gate.cpp b/targettests/infleqtion/swap_gate.cpp new file mode 120000 index 0000000000..2b441fc25d --- /dev/null +++ b/targettests/infleqtion/swap_gate.cpp @@ -0,0 +1 @@ +../execution/swap_gate.cpp \ No newline at end of file diff --git a/targettests/infleqtion/test-int8_t.cpp b/targettests/infleqtion/test-int8_t.cpp new file mode 120000 index 0000000000..0f31415598 --- /dev/null +++ b/targettests/infleqtion/test-int8_t.cpp @@ -0,0 +1 @@ +../execution/int8_t.cpp \ No newline at end of file diff --git a/targettests/infleqtion/test-int8_t_free_func.cpp b/targettests/infleqtion/test-int8_t_free_func.cpp new file mode 120000 index 0000000000..bd446321b6 --- /dev/null +++ b/targettests/infleqtion/test-int8_t_free_func.cpp @@ -0,0 +1 @@ +../execution/int8_t_free_func.cpp \ No newline at end of file diff --git a/targettests/infleqtion/variable_size_qreg.cpp b/targettests/infleqtion/variable_size_qreg.cpp new file mode 120000 index 0000000000..e2a775d5c5 --- /dev/null +++ b/targettests/infleqtion/variable_size_qreg.cpp @@ -0,0 +1 @@ +../execution/variable_size_qreg.cpp \ No newline at end of file diff --git a/targettests/lit.cfg.py b/targettests/lit.cfg.py index c0f831c0b5..697ac662af 100644 --- a/targettests/lit.cfg.py +++ b/targettests/lit.cfg.py @@ -24,7 +24,7 @@ # Exclude a list of directories from the test suite: # - 'Inputs' contain auxiliary inputs for various tests. -local_excludes = ['anyon', 'ionq', 'iqm', 'oqc', 'quantinuum', 'fermioniq' +local_excludes = ['anyon', 'ionq', 'iqm', 'oqc', 'quantinuum', 'fermioniq', 'infleqtion', 'Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt'] config.excludes = [exclude for exclude in config.excludes] + local_excludes diff --git a/unittests/backends/CMakeLists.txt b/unittests/backends/CMakeLists.txt index 56dc3a3d2f..2c8250a55b 100644 --- a/unittests/backends/CMakeLists.txt +++ b/unittests/backends/CMakeLists.txt @@ -10,6 +10,7 @@ find_package(Python COMPONENTS Interpreter) if (OPENSSL_FOUND AND CUDAQ_ENABLE_PYTHON AND CUDAQ_TEST_MOCK_SERVERS) add_subdirectory(anyon) add_subdirectory(braket) + add_subdirectory(infleqtion) add_subdirectory(ionq) add_subdirectory(iqm) add_subdirectory(oqc) diff --git a/unittests/backends/infleqtion/CMakeLists.txt b/unittests/backends/infleqtion/CMakeLists.txt new file mode 100644 index 0000000000..f06f48a5c3 --- /dev/null +++ b/unittests/backends/infleqtion/CMakeLists.txt @@ -0,0 +1,28 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +add_executable(test_infleqtion InfleqtionTester.cpp) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) + target_link_options(test_infleqtion PRIVATE -Wl,--no-as-needed) +endif() +target_compile_definitions(test_infleqtion PRIVATE -DNVQIR_BACKEND_NAME=infleqtion) +target_include_directories(test_infleqtion PRIVATE ../..) +target_link_libraries(test_infleqtion + PRIVATE fmt::fmt-header-only + cudaq-common + cudaq + cudaq-builder + cudaq-mlir-runtime + cudaq-rest-qpu + cudaq-spin + cudaq-platform-default + gtest_main) + + +configure_file("InfleqtionStartServerAndTest.sh.in" "${CMAKE_BINARY_DIR}/unittests/backends/infleqtion/InfleqtionStartServerAndTest.sh" @ONLY) +add_test(NAME infleqtion-tests COMMAND bash InfleqtionStartServerAndTest.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests/backends/infleqtion/) diff --git a/unittests/backends/infleqtion/InfleqtionStartServerAndTest.sh.in b/unittests/backends/infleqtion/InfleqtionStartServerAndTest.sh.in new file mode 100644 index 0000000000..7c2bd59619 --- /dev/null +++ b/unittests/backends/infleqtion/InfleqtionStartServerAndTest.sh.in @@ -0,0 +1,43 @@ +#!/bin/bash + +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +checkServerConnection() { + PYTHONPATH=@CMAKE_BINARY_DIR@/python @Python_EXECUTABLE@ - << EOF +import socket +try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(("localhost", 62447)) + s.close() +except Exception: + exit(1) +EOF +} + +# Launch the fake server +PYTHONPATH=@CMAKE_BINARY_DIR@/python @Python_EXECUTABLE@ @CMAKE_SOURCE_DIR@/utils/mock_qpu/infleqtion/__init__.py & +# we'll need the process id to kill it +pid=$(echo "$!") +n=0 +while ! checkServerConnection; do + sleep 1 + n=$((n+1)) + if [ "$n" -eq "10" ]; then + kill -INT $pid + exit 99 + fi +done +# Run the tests +./test_infleqtion +# Did they fail? +testsPassed=$? +# kill the server +kill -INT $pid +# return success / failure +exit $testsPassed diff --git a/unittests/backends/infleqtion/InfleqtionTester.cpp b/unittests/backends/infleqtion/InfleqtionTester.cpp new file mode 100644 index 0000000000..85125c5a21 --- /dev/null +++ b/unittests/backends/infleqtion/InfleqtionTester.cpp @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "CUDAQTestUtils.h" +#include "common/FmtCore.h" +#include "cudaq/algorithm.h" +#include +#include +#include + +std::string mockPort = "62447"; +std::string backendStringTemplate = + "infleqtion;emulate;false;url;http://localhost:{}"; + +bool isValidExpVal(double value) { + // give us some wiggle room while keep the tests fast + return value < -1.1 && value > -2.3; +} + +CUDAQ_TEST(InfleqtionTester, checkSampleSync) { + auto backendString = + fmt::format(fmt::runtime(backendStringTemplate), mockPort); + + auto &platform = cudaq::get_platform(); + platform.setTargetBackend(backendString); + + auto kernel = cudaq::make_kernel(); + auto qubit = kernel.qalloc(2); + kernel.h(qubit[0]); + kernel.mz(qubit[0]); + + auto counts = cudaq::sample(kernel); + counts.dump(); + EXPECT_EQ(counts.size(), 2); +} + +CUDAQ_TEST(InfleqtionTester, checkSampleAsync) { + auto backendString = + fmt::format(fmt::runtime(backendStringTemplate), mockPort); + + auto &platform = cudaq::get_platform(); + platform.setTargetBackend(backendString); + + auto kernel = cudaq::make_kernel(); + auto qubit = kernel.qalloc(2); + kernel.h(qubit[0]); + kernel.mz(qubit[0]); + + auto future = cudaq::sample_async(kernel); + auto counts = future.get(); + EXPECT_EQ(counts.size(), 2); +} + +CUDAQ_TEST(InfleqtionTester, checkSampleAsyncLoadFromFile) { + auto backendString = + fmt::format(fmt::runtime(backendStringTemplate), mockPort); + + auto &platform = cudaq::get_platform(); + platform.setTargetBackend(backendString); + + auto kernel = cudaq::make_kernel(); + auto qubit = kernel.qalloc(2); + kernel.h(qubit[0]); + kernel.mz(qubit[0]); + + // Can sample asynchronously and get a future + auto future = cudaq::sample_async(kernel); + + // Future can be persisted for later + { + std::ofstream out("saveMe.json"); + out << future; + } + + // Later you can come back and read it in + cudaq::async_result readIn; + std::ifstream in("saveMe.json"); + in >> readIn; + + // Get the results of the read in future. + auto counts = readIn.get(); + EXPECT_EQ(counts.size(), 2); + + std::remove("saveMe.json"); +} + +int main(int argc, char **argv) { + setenv("SUPERSTAQ_API_KEY", "00000000000000000000000000000000", 0); + ::testing::InitGoogleTest(&argc, argv); + auto ret = RUN_ALL_TESTS(); + return ret; +} diff --git a/utils/mock_qpu/__init__.py b/utils/mock_qpu/__init__.py index 1f3801628a..f28edfeb69 100644 --- a/utils/mock_qpu/__init__.py +++ b/utils/mock_qpu/__init__.py @@ -8,6 +8,7 @@ from .anyon import * from .braket import * +from .infleqtion import * from .ionq import * from .iqm import * from .quantinuum import * diff --git a/utils/mock_qpu/infleqtion/__init__.py b/utils/mock_qpu/infleqtion/__init__.py new file mode 100644 index 0000000000..7c71e8264e --- /dev/null +++ b/utils/mock_qpu/infleqtion/__init__.py @@ -0,0 +1,95 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +from fastapi import FastAPI, HTTPException, Header +from typing import Union +import uvicorn, uuid +from pydantic import BaseModel + +# Define the REST Server App +app = FastAPI() + + +class Input(BaseModel): + format: str + data: str + + +# Jobs look like the following type +class Job(BaseModel): + qasm_strs: str + shots: int + target: str + + +# Keep track of Job Ids to their Names +createdJobs = {} + +# Could how many times the client has requested the Job +countJobGetRequests = 0 + +# Save how many qubits were needed for each test (emulates real backend) +numQubitsRequired = 0 + + +# Here we test that the login endpoint works +@app.post("/login") +async def login(token: Union[str, None] = Header(alias="Authorization", + default=None)): + if token == None: + raise HTTPException(status_code(401), detail="Credentials not provided") + return {"id-token": "hello", "refresh-token": "refreshToken"} + + +# Here we expose a way to post jobs, +# Must have a Access Token +# with entry_point tag +@app.post("/v0.2.0/jobs") +async def postJob(job: Job, + token: Union[str, None] = Header(alias="Authorization", + default=None)): + global createdJobs, shots, numQubitsRequired + + if token == None: + raise HTTPException(status_code(401), detail="Credentials not provided") + + print('Posting job with shots = ', job.shots) + newId = str(uuid.uuid4()) + # Job "created", return the id + return {"job_ids": [newId]} + + +# Retrieve the job, simulate having to wait by counting to 3 +# until we return the job results +@app.get("/v0.2.0/job/{id}") +async def getJob(id: str): + print("Getting Job") + global countJobGetRequests, createdJobs, numQubitsRequired + + # Simulate asynchronous execution + if countJobGetRequests < 3: + countJobGetRequests += 1 + return {"status": "running"} + + countJobGetRequests = 0 + res = { + 'status': 'Done', + "samples": { + "11": 49, + "00": 51 + }, + } + return res + + +def startServer(port): + uvicorn.run(app, port=port, host='0.0.0.0', log_level="info") + + +if __name__ == '__main__': + startServer(62447) From 8f288a3dff6dbe0c4067b311742a5e6f86c9fc51 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Tue, 10 Dec 2024 19:21:21 +0100 Subject: [PATCH 16/26] Fixing nightly integration tests (#2460) Signed-off-by: Bettina Heim --- .github/workflows/integration_tests.yml | 82 ++++++++++++++++++++++--- docker/release/cudaq.nvqc.Dockerfile | 2 +- scripts/release.sh | 13 +++- 3 files changed, 86 insertions(+), 11 deletions(-) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index e4bd272293..55d329b93f 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -63,7 +63,6 @@ on: - cron: 0 3 * * * env: - # NGC nv-quantum organization: pnyjrcojiblh NGC_QUANTUM_ORG: pnyjrcojiblh NGC_QUANTUM_TEAM: cuda-quantum NVQC_FUNCTION_ID: 3bfa0342-7d2a-4f1b-8e81-b6608d28ca7d @@ -75,30 +74,90 @@ jobs: # We need this job purely to choose the container image values because the # `env` context is unavailable outside of "steps" contexts. setup: - name: Set variables + name: Configure jobs runs-on: ubuntu-latest + permissions: + packages: write + + environment: + name: ghcr-deployment + url: ${{ vars.deployment_url }} + outputs: - cudaq_test_image: ${{ steps.vars.outputs.cudaq_test_image }} - cudaq_nvqc_deploy_image: ${{ steps.vars.outputs.cudaq_nvqc_deploy_image }} + cudaq_test_image: ${{ steps.vars.outputs.cudaq_nightly_image }}@${{ steps.test_image.outputs.digest }} + cudaq_nvqc_deploy_image: ${{ inputs.cudaq_nvqc_deploy_image || format('{0}@{1}', steps.vars.outputs.cudaq_nightly_image, steps.test_image.outputs.digest) }} + steps: - name: Set variables id: vars run: | - echo "cudaq_test_image=${{ inputs.cudaq_test_image || vars.cudaq_test_image }}" >> $GITHUB_OUTPUT - echo "cudaq_nvqc_deploy_image=${{ inputs.cudaq_nvqc_deploy_image || vars.cudaq_test_image }}" >> $GITHUB_OUTPUT + cudaq_test_image=${{ inputs.cudaq_test_image || vars.cudaq_test_image }} + cudaq_nightly_image=ghcr.io/nvidia/${{ vars.packages_prefix }}cuda-quantum + + sudo apt-get update && sudo apt-get install -y --no-install-recommends curl + curl -L https://github.com/regclient/regclient/releases/latest/download/regctl-linux-amd64 > regctl + chmod 755 regctl + + manifest=`./regctl image manifest $cudaq_test_image --format "{{ json . }}"` + platforms=`echo $manifest | jq -r '.manifests | map("\(.platform.os)/\(.platform.architecture)") | .[]'` + echo "FROM $cudaq_test_image" >> test_image.Dockerfile + + echo "platforms=$(echo $platforms | tr ' ' ,)" >> $GITHUB_OUTPUT + echo "cudaq_nightly_image=$cudaq_nightly_image" >> $GITHUB_OUTPUT + + - name: Log in to GitHub CR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Set up context for buildx + run: | + docker context create builder_context + + - name: Set up buildx runner + uses: docker/setup-buildx-action@v3 + with: + endpoint: builder_context + + - name: Extract metadata + id: metadata + uses: docker/metadata-action@v5 + with: + images: ${{ steps.vars.outputs.cudaq_nightly_image }} + flavor: latest=false + tags: type=raw,value=nightly + labels: | + org.opencontainers.image.title=cuda-quantum + org.opencontainers.image.description=CUDA-Q image used for nightly integration tests + + - name: Update nightly image on GHCR + id: test_image + uses: docker/build-push-action@v5 + with: + context: . + file: test_image.Dockerfile + tags: ${{ steps.metadata.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} + platforms: ${{ steps.vars.outputs.platforms }} + push: true metadata: name: Retrieve commit info runs-on: ubuntu-latest needs: setup + container: image: ${{ needs.setup.outputs.cudaq_test_image }} options: --user root credentials: username: ${{ github.actor }} password: ${{ github.token }} + outputs: cudaq_commit: ${{ steps.commit-sha.outputs.sha }} + steps: - name: Get commit SHA id: commit-sha @@ -248,6 +307,9 @@ jobs: container: image: ${{ needs.setup.outputs.cudaq_test_image }} options: --user root + credentials: + username: ${{ github.actor }} + password: ${{ github.token }} steps: - name: Get code @@ -620,10 +682,16 @@ jobs: packages: read # Must have environment protection - environment: ghcr-deployment + environment: + name: ghcr-deployment + url: ${{ vars.deployment_url }} + container: image: ${{ needs.setup.outputs.cudaq_test_image }} options: --user root + credentials: + username: ${{ github.actor }} + password: ${{ github.token }} steps: - name: Get code diff --git a/docker/release/cudaq.nvqc.Dockerfile b/docker/release/cudaq.nvqc.Dockerfile index e5d3a9fcf5..56348e7aa3 100644 --- a/docker/release/cudaq.nvqc.Dockerfile +++ b/docker/release/cudaq.nvqc.Dockerfile @@ -10,7 +10,7 @@ # # Usage: # Must be built from the repo root with: -# DOCKER_BUILDKIT=1 docker build -f docker/release/cudaq.nvqc.Dockerfile . --output out +# docker build -f docker/release/cudaq.nvqc.Dockerfile . # Base image is CUDA-Q image ARG base_image=nvcr.io/nvidia/nightly/cuda-quantum:cu12-latest diff --git a/scripts/release.sh b/scripts/release.sh index 38a17346cb..c8bc12abf8 100644 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -16,10 +16,17 @@ version_regex="([0-9]{1,}\.)+[0-9]{1,}\S*" versions=`gh release list -R nvidia/cuda-quantum --exclude-drafts --exclude-pre-releases | egrep -o "$version_regex" | sort -r -V` last_release=`echo $versions | cut -d ' ' -f 1` -current_release="0.9.0" +current_release="$1" +if [ -z "$current_release" ]; then + echo "Warning: no version number specified for the new release." + rel_branch=main +else + rel_branch=releases/v$current_release +fi author="" # insert your name to show only your PRs -git pull && git log releases/v$current_release...releases/v$last_release --cherry-pick --left-only --no-merges --oneline --author="$author" | egrep -o '\(#[0-9]*\)$' > commits.txt +git pull || echo "Warning: failed to pull updates" +git log $rel_branch...releases/v$last_release --cherry-pick --left-only --no-merges --oneline --author="$author" | egrep -o '\(#[0-9]*\)$' > commits.txt for pr in `cat commits.txt`; do maintenance=`gh pr view ${pr: 2: -1} --json labels --jq 'any(.labels.[]; .name == "maintenance")'` @@ -29,7 +36,7 @@ for pr in `cat commits.txt`; do if [ -z "$milestone" ]; then echo "Missing milestone for PR ${pr: 2: -1} by $pr_author." - elif [ "$(echo "$milestone" | egrep -o "$version_regex" || true)" == "$current_release" ]; then + elif [ -z "$current_release" ] || [ "$(echo "$milestone" | egrep -o "$version_regex" || true)" == "$current_release" ]; then labels=`gh pr view ${pr: 2: -1} --json labels --jq '.labels.[].name'` echo "Labels for PR ${pr: 2: -1} by $pr_author: $labels" fi From 1e383a65b56d3e7c91f4c6641b7baa8a895d66bb Mon Sep 17 00:00:00 2001 From: caiyunh Date: Wed, 11 Dec 2024 04:52:35 +0800 Subject: [PATCH 17/26] Generate coverage data when pusing to main (#2442) Signed-off-by: Iris Huang Signed-off-by: Bettina Heim Co-authored-by: Iris Huang Co-authored-by: Bettina Heim --- .github/workflows/deployments.yml | 49 +++++++++++++++++++++++-------- .github/workflows/generate_cc.yml | 23 ++++++++------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/.github/workflows/deployments.yml b/.github/workflows/deployments.yml index caaf5358b5..235bfbe6e1 100644 --- a/.github/workflows/deployments.yml +++ b/.github/workflows/deployments.yml @@ -63,12 +63,14 @@ jobs: pull_request_number: ${{ steps.pr_info.outputs.pr_number }} pull_request_base: ${{ steps.pr_info.outputs.pr_base }} pull_request_commit: ${{ steps.pr_info.outputs.merge_commit }} - llvm_commit: ${{ steps.repo_info.outputs.llvm_commit }} - pybind11_commit: ${{ steps.repo_info.outputs.pybind11_commit }} + llvm_commit: ${{ steps.build_config.outputs.llvm_commit }} + pybind11_commit: ${{ steps.build_config.outputs.pybind11_commit }} cache_base: ${{ steps.build_info.outputs.cache_base }} cache_target: ${{ steps.build_info.outputs.cache_target }} multi_platform: ${{ steps.build_info.outputs.multi_platform }} platforms: ${{ steps.build_info.outputs.platforms }} + build_dependencies: ${{ steps.build_config.outputs.build_dependencies }} + create_packages: ${{ steps.build_config.outputs.create_packages }} environment: ${{ steps.build_info.outputs.environment }} steps: @@ -159,15 +161,22 @@ jobs: ref: "${{ steps.pr_info.outputs.merge_commit }}" - name: Configure build - id: repo_info + id: build_config run: | echo "llvm_commit=$(git rev-parse @:./tpls/llvm)" >> $GITHUB_OUTPUT echo "pybind11_commit=$(git rev-parse @:./tpls/pybind11)" >> $GITHUB_OUTPUT + if ${{ github.event_name != 'workflow_run' || steps.pr_info.outputs.pr_number != '' }}; then + echo "build_dependencies=true" >> $GITHUB_OUTPUT + fi + if ${{ github.event_name == 'workflow_dispatch' && ! inputs.update_registry_cache }}; then + echo "create_packages=true" >> $GITHUB_OUTPUT + fi + devdeps: name: Build dev dependencies needs: metadata - if: github.event_name != 'workflow_run' || needs.metadata.outputs.pull_request_number != '' + if: needs.metadata.outputs.build_dependencies == 'true' strategy: matrix: platform: ${{ fromJson(needs.metadata.outputs.multi_platform || needs.metadata.outputs.platforms).ids }} @@ -195,7 +204,7 @@ jobs: wheeldeps: name: Build wheel dependencies needs: metadata - if: github.event_name != 'workflow_run' || needs.metadata.outputs.pull_request_number != '' + if: needs.metadata.outputs.build_dependencies == 'true' strategy: matrix: # There are currently no multi-platform manylinux images available. @@ -229,7 +238,7 @@ jobs: source_build: name: Build cross-platform dependencies needs: metadata - if: github.event_name != 'workflow_run' || needs.metadata.outputs.pull_request_number != '' + if: needs.metadata.outputs.build_dependencies == 'true' strategy: matrix: platform: ${{ fromJson(needs.metadata.outputs.platforms).ids }} @@ -260,7 +269,7 @@ jobs: openmpi: name: Build Open MPI needs: metadata - if: github.event_name != 'workflow_run' || needs.metadata.outputs.pull_request_number != '' + if: needs.metadata.outputs.build_dependencies == 'true' strategy: matrix: platform: ${{ fromJson(needs.metadata.outputs.multi_platform || needs.metadata.outputs.platforms).ids }} @@ -311,13 +320,12 @@ jobs: # https://github.com/actions/runner/pull/2477 config: name: Configure build - needs: [devdeps, wheeldeps, source_build, openmpi] - if: github.event_name == 'workflow_dispatch' && ! inputs.update_registry_cache + needs: [metadata, devdeps, wheeldeps, source_build, openmpi] + if: needs.metadata.outputs.create_packages == 'true' runs-on: ubuntu-latest outputs: json: "${{ steps.read_json.outputs.result }}" - devdeps_toolchain: gcc11 steps: - uses: cloudposse/github-action-matrix-outputs-read@1.0.0 @@ -325,6 +333,23 @@ jobs: with: matrix-step-name: dev_environment + coverage: + name: Update code coverage + needs: [metadata, config] + if: needs.metadata.outputs.multi_platform != '' + strategy: + matrix: + platform: [amd64] + toolchain: [clang16] + fail-fast: false + uses: ./.github/workflows/generate_cc.yml + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + platform: linux/${{ matrix.platform }} + devdeps_image: ${{ fromJson(needs.config.outputs.json).image_hash[format('{0}-{1}', fromJson(needs.metadata.outputs.multi_platform).ids[0], matrix.toolchain)] }} + export_environment: false + extdevdeps: name: Create dev environment needs: [metadata, config, openmpi] @@ -340,10 +365,10 @@ jobs: with: platforms: ${{ fromJson(needs.metadata.outputs.multi_platform || needs.metadata.outputs.platforms)[format('{0}', matrix.platform)].docker_flag }} dockerfile: build/devdeps.ext.Dockerfile - build_config_id: cu${{ matrix.cuda_version }}-${{ needs.config.outputs.devdeps_toolchain }} + build_config_id: cu${{ matrix.cuda_version }}-gcc11 build_args: | cuda_version=${{ matrix.cuda_version }} - base_image=${{ fromJson(needs.config.outputs.json).image_hash[format('{0}-{1}', matrix.platform, needs.config.outputs.devdeps_toolchain)] }} + base_image=${{ fromJson(needs.config.outputs.json).image_hash[format('{0}-gcc11', matrix.platform)] }} ompidev_image=${{ fromJson(needs.config.outputs.json).image_hash[format('{0}-cu{1}-ompi', matrix.platform, matrix.cuda_version)] }} ${{ matrix.cuda_version != '11.8' && 'cuda_packages=cuda-cudart cuda-nvrtc cuda-compiler libcublas-dev libcusolver libnvjitlink' || '' }} registry_cache_from: ${{ needs.metadata.outputs.cache_base }} diff --git a/.github/workflows/generate_cc.yml b/.github/workflows/generate_cc.yml index 463d0e0c6a..8df4b23a49 100644 --- a/.github/workflows/generate_cc.yml +++ b/.github/workflows/generate_cc.yml @@ -9,10 +9,10 @@ on: required: false type: string devdeps_cache: - required: true + required: false type: string devdeps_archive: - required: true + required: false type: string export_environment: required: false @@ -33,24 +33,25 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - - - name: Restore environment - id: restore_devdeps - if: inputs.devdeps_image == '' - uses: actions/cache/restore@v4 with: - path: ${{ inputs.devdeps_archive }} - key: ${{ inputs.devdeps_cache }} - fail-on-cache-miss: true + persist-credentials: false - name: Log in to GitHub CR - if: inputs.devdeps_image != '' uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ github.token }} + - name: Restore environment + id: restore_devdeps + if: inputs.devdeps_cache && inputs.devdeps_archive + uses: actions/cache/restore@v4 + with: + path: ${{ inputs.devdeps_archive }} + key: ${{ inputs.devdeps_cache }} + fail-on-cache-miss: true + - name: Set up context for buildx run: | docker context create builder_context From b089b03cafeafc2619712565c8c7f03136346118 Mon Sep 17 00:00:00 2001 From: Pradnya Khalate <148914294+khalatepradnya@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:06:26 -0800 Subject: [PATCH 18/26] Follow-up for the `infleqtion` target - `cu1` and `cu3` are supported (#2461) * Decomposition pattern no longer required * Added test Signed-off-by: Pradnya Khalate --- python/tests/backends/test_Infleqtion.py | 2 +- .../platform/default/rest/helpers/infleqtion/infleqtion.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tests/backends/test_Infleqtion.py b/python/tests/backends/test_Infleqtion.py index 24c4a11d24..49b2eebc66 100644 --- a/python/tests/backends/test_Infleqtion.py +++ b/python/tests/backends/test_Infleqtion.py @@ -78,7 +78,7 @@ def all_gates(): rz.ctrl(np.pi, qubits[1], qubits[0]) s.ctrl(qubits[0], qubits[1]) t.ctrl(qubits[1], qubits[0]) - # u3.ctrl(0.0, np.pi / 2, np.pi, qubits[0], qubits[1]) + u3.ctrl(0.0, np.pi / 2, np.pi, qubits[0], qubits[1]) mz(qubits) qreg = cudaq.qvector(3) diff --git a/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml b/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml index 5370880e27..31c10e38c6 100644 --- a/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml +++ b/runtime/cudaq/platform/default/rest/helpers/infleqtion/infleqtion.yml @@ -17,7 +17,7 @@ config: # Tell NVQ++ to generate glue code to set the target backend name gen-target-backend: true # Define the lowering pipeline - platform-lowering-config: "func.func(const-prop-complex,canonicalize,cse,lift-array-alloc),globalize-array-values,func.func(state-prep),unitary-synthesis,canonicalize,apply-op-specialization,aggressive-early-inlining,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(multicontrol-decomposition),decomposition{enable-patterns=SToR1,TToR1,SwapToCX,CCZToCX,CR1ToCX,CRyToCX,CRxToCX,R1AdjToR1,RxAdjToRx,RyAdjToRy,RzAdjToRz},func.func(memtoreg{quantum=0}),symbol-dce" + platform-lowering-config: "func.func(const-prop-complex,canonicalize,cse,lift-array-alloc),globalize-array-values,func.func(state-prep),unitary-synthesis,canonicalize,apply-op-specialization,aggressive-early-inlining,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(multicontrol-decomposition),decomposition{enable-patterns=SToR1,TToR1,CCZToCX,CRyToCX,CRxToCX,R1AdjToR1,RxAdjToRx,RyAdjToRy,RzAdjToRz},func.func(memtoreg{quantum=0}),symbol-dce" # Tell the rest-qpu that we are generating OpenQASM 2.0. codegen-emission: qasm2 # Library mode is only for simulators, physical backends must turn this off From 72eab568a4ccefcf30ec50c6136744a49f5c1021 Mon Sep 17 00:00:00 2001 From: Pradnya Khalate <148914294+khalatepradnya@users.noreply.github.com> Date: Wed, 11 Dec 2024 02:28:56 -0800 Subject: [PATCH 19/26] [bug-fix] Custom operations - disallow `qvector` arguments (#2454) Signed-off-by: Pradnya Khalate --- python/cudaq/kernel/ast_bridge.py | 12 +++++- python/tests/custom/test_custom_operations.py | 39 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/python/cudaq/kernel/ast_bridge.py b/python/cudaq/kernel/ast_bridge.py index 5f566768c2..d76a802d72 100644 --- a/python/cudaq/kernel/ast_bridge.py +++ b/python/cudaq/kernel/ast_bridge.py @@ -1826,7 +1826,11 @@ def bodyBuilder(iterVal): targets = [self.popValue() for _ in range(numTargets)] targets.reverse() - self.checkControlAndTargetTypes([], targets) + for i, t in enumerate(targets): + if not quake.RefType.isinstance(t.type): + self.emitFatalError( + f'invalid target operand {i}, broadcasting is not supported on custom operations.' + ) globalName = f'{nvqppPrefix}{node.func.id}_generator_{numTargets}.rodata' @@ -2678,6 +2682,12 @@ def bodyBuilder(iterVal): targets = [self.popValue() for _ in range(numTargets)] targets.reverse() + for i, t in enumerate(targets): + if not quake.RefType.isinstance(t.type): + self.emitFatalError( + f'invalid target operand {i}, broadcasting is not supported on custom operations.' + ) + globalName = f'{nvqppPrefix}{node.func.value.id}_generator_{numTargets}.rodata' currentST = SymbolTable(self.module.operation) diff --git a/python/tests/custom/test_custom_operations.py b/python/tests/custom/test_custom_operations.py index ed2f3cfa49..e1772b2ebe 100644 --- a/python/tests/custom/test_custom_operations.py +++ b/python/tests/custom/test_custom_operations.py @@ -230,6 +230,45 @@ def bell(): error) +def test_bug_2452(): + cudaq.register_operation("custom_i", np.array([1, 0, 0, 1])) + + @cudaq.kernel + def kernel1(): + qubits = cudaq.qvector(2) + custom_i(qubits) + + with pytest.raises(RuntimeError) as error: + kernel1.compile() + assert 'broadcasting is not supported on custom operations' in repr(error) + + cudaq.register_operation("custom_x", np.array([0, 1, 1, 0])) + + @cudaq.kernel + def kernel2(): + qubit = cudaq.qubit() + ancilla = cudaq.qvector(2) + x(ancilla) + custom_x.ctrl(ancilla, qubit) # `controls` can be `qvector` + + counts = cudaq.sample(kernel2) + assert len(counts) == 1 and '111' in counts + + cudaq.register_operation( + "custom_cz", np.array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + -1])) + + @cudaq.kernel + def kernel3(): + qubits = cudaq.qvector(2) + custom_cz(qubits) + + with pytest.raises(RuntimeError) as error: + cudaq.sample(kernel3) + assert 'invalid number of arguments (1) passed to custom_cz (requires 2 arguments)' in repr( + error) + + # leave for gdb debugging if __name__ == "__main__": loc = os.path.abspath(__file__) From 4ea2f733bf025c18435aa79b8e6eca3959cfd34d Mon Sep 17 00:00:00 2001 From: Markus Pfundstein Date: Wed, 11 Dec 2024 11:45:26 +0100 Subject: [PATCH 20/26] Fix wrong parameters in docs for Fermioniq backend (#2367) * DCO Remediation Commit for Markus Pfundstein I, Markus Pfundstein , hereby add my Signed-off-by to this commit: a68a8d99eb3e2f7a34cce42f9d87213f23072b04 Signed-off-by: Markus Pfundstein --- docs/sphinx/using/backends/simulators.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sphinx/using/backends/simulators.rst b/docs/sphinx/using/backends/simulators.rst index 70a94343a5..a3dba35d92 100644 --- a/docs/sphinx/using/backends/simulators.rst +++ b/docs/sphinx/using/backends/simulators.rst @@ -522,7 +522,7 @@ compute expectation values of observables. .. code:: python cudaq.set_target("fermioniq", **{ - "remote-config": remote_config_id + "remote_config": remote_config_id }) For a comprehensive list of all remote configurations, please contact Fermioniq directly. @@ -533,15 +533,15 @@ compute expectation values of observables. .. code:: python cudaq.set_target("fermioniq", **{ - "project-id": project_id + "project_id": project_id }) - To specify the bond dimension, you can pass the ``fermioniq-bond-dim`` parameter. + To specify the bond dimension, you can pass the ``bond_dim`` parameter. .. code:: python cudaq.set_target("fermioniq", **{ - "bond-dim": 5 + "bond_dim": 5 }) .. tab:: C++ From 538458cbeecb7d091cc105821a931ef97600ec7b Mon Sep 17 00:00:00 2001 From: Ben Howe <141149032+bmhowe23@users.noreply.github.com> Date: Wed, 11 Dec 2024 04:31:56 -0800 Subject: [PATCH 21/26] Add unintentionally excluded tests to Publishing workflow (#2038) Signed-off-by: Bettina Heim Co-authored-by: Bettina Heim --- .github/workflows/publishing.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publishing.yml b/.github/workflows/publishing.yml index 80a21942f9..cfdb5068b2 100644 --- a/.github/workflows/publishing.yml +++ b/.github/workflows/publishing.yml @@ -1128,14 +1128,14 @@ jobs: tar xf /tmp/packages/${cudaq_metapackage}.tar.gz && mv -v ${cudaq_metapackage}/README.md . rm -rf ${cudaq_metapackage} && readme=README.md - # Setup links for validate_pycudaq.sh script - ln -s $GITHUB_WORKSPACE/scripts/validate_pycudaq.sh . - ln -s $GITHUB_WORKSPACE/docs/sphinx/examples/python /tmp/examples - ln -s $GITHUB_WORKSPACE/docs/sphinx/applications/python /tmp/applications - ln -s $GITHUB_WORKSPACE/docs/sphinx/targets/python /tmp/targets - ln -s $GITHUB_WORKSPACE/docs/sphinx/snippets/python /tmp/snippets - ln -s $GITHUB_WORKSPACE/python/tests /tmp/tests - ln -s $GITHUB_WORKSPACE/$readme /tmp/README.md + # Setup files for validate_pycudaq.sh script + cp $GITHUB_WORKSPACE/scripts/validate_pycudaq.sh . + cp -r $GITHUB_WORKSPACE/docs/sphinx/examples/python /tmp/examples/ + cp -r $GITHUB_WORKSPACE/docs/sphinx/applications/python /tmp/applications/ + cp -r $GITHUB_WORKSPACE/docs/sphinx/targets/python /tmp/targets/ + cp -r $GITHUB_WORKSPACE/docs/sphinx/snippets/python /tmp/snippets/ + cp -r $GITHUB_WORKSPACE/python/tests /tmp/tests/ + cp $GITHUB_WORKSPACE/$readme /tmp/README.md # Run the script w/ -q to run a shortened test set +e # Allow script to keep going through errors (needed for skipped tests) From 77801540850e1f40c67865600edb748dcc6fff81 Mon Sep 17 00:00:00 2001 From: Bharath Thotakura <113555655+bharat-thotakura@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:58:45 -0600 Subject: [PATCH 22/26] Documentation for `infleqtion` target (#2464) Signed-off-by: Bharath Signed-off-by: Bettina Heim Co-authored-by: Bettina Heim --- .../workflows/config/spelling_allowlist.txt | 1 + .../python/logical_aim_sqale.ipynb | 1356 +++++++++++++++++ docs/sphinx/targets/cpp/infleqtion.cpp | 65 + docs/sphinx/targets/python/infleqtion.py | 54 + docs/sphinx/using/applications.rst | 5 +- docs/sphinx/using/backends/backends.rst | 5 +- docs/sphinx/using/backends/hardware.rst | 122 ++ .../using/examples/hardware_providers.rst | 17 +- 8 files changed, 1620 insertions(+), 5 deletions(-) create mode 100644 docs/sphinx/applications/python/logical_aim_sqale.ipynb create mode 100644 docs/sphinx/targets/cpp/infleqtion.cpp create mode 100644 docs/sphinx/targets/python/infleqtion.py diff --git a/.github/workflows/config/spelling_allowlist.txt b/.github/workflows/config/spelling_allowlist.txt index e74c23ba43..19fcb2d34f 100644 --- a/.github/workflows/config/spelling_allowlist.txt +++ b/.github/workflows/config/spelling_allowlist.txt @@ -46,6 +46,7 @@ Hamiltonian Hamiltonians IQM InfiniBand +Infleqtion IonQ JIT JSON diff --git a/docs/sphinx/applications/python/logical_aim_sqale.ipynb b/docs/sphinx/applications/python/logical_aim_sqale.ipynb new file mode 100644 index 0000000000..f51bd10294 --- /dev/null +++ b/docs/sphinx/applications/python/logical_aim_sqale.ipynb @@ -0,0 +1,1356 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anderson Impurity Model ground state solver on Infleqtion's Sqale" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ground state quantum chemistry—computing total energies of molecular configurations to within chemical accuracy—is perhaps the most highly-touted industrial application of fault-tolerant quantum computers. Strongly correlated materials, for example, are particularly interesting, and tools like dynamical mean-field theory (DMFT) allow one to account for the effect of their strong, localized electronic correlations. These DMFT models help predict material properties by approximating the system as a single site impurity inside a “bath” that encompasses the rest of the system. Simulating such dynamics can be a tough task using classical methods, but can be done efficiently on a quantum computer via quantum simulation.\n", + "\n", + "In this notebook, we showcase a workflow for preparing the ground state of the minimal single-impurity Anderson model (SIAM) using the Hamiltonian Variational Ansatz for a range of realistic parameters. As a first step towards running DMFT on a fault-tolerant quantum computer, we will use logical qubits encoded in the `[[4, 2, 2]]` code. Using this workflow, we will obtain the ground state energy estimates via noisy simulation, and then also execute the corresponding optimized circuits on Infleqtion's gate-based neutral-atom quantum computer, making the benefits of logical qubits apparent. More details can be found in our [paper](https://arxiv.org/abs/2412.07670)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This demo notebook uses CUDA-Q (`cudaq`) and a CUDA-QX library, `cudaq-solvers`; let us first begin by importing (and installing as needed) these packages:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import cudaq_solvers as solvers\n", + " import cudaq\n", + " import matplotlib.pyplot as plt\n", + "except ImportError:\n", + " print(\"Installing required packages...\")\n", + " %pip install --quiet 'cudaq-solvers' 'matplotlib'\n", + " print(\"Installed `cudaq`, `cudaq-solvers`, and `matplotlib` packages.\")\n", + " print(\"You may need to restart the kernel to import newly installed packages.\")\n", + " import cudaq_solvers as solvers\n", + " import cudaq\n", + " import matplotlib.pyplot as plt\n", + "\n", + "from collections.abc import Mapping, Sequence\n", + "import numpy as np\n", + "from scipy.optimize import minimize\n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Performing logical Variational Quantum Eigensolver (VQE) with CUDA-QX" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To prepare our ground state quantum Anderson impurity model circuits (referred to as AIM circuits in this notebook for short), we use VQE to train an ansatz to minimize a Hamiltonian and obtain optimal angles that can be used to set the AIM circuits. As described in our [paper](https://arxiv.org/abs/2412.07670), the associated restricted Hamiltonian for our SIAM can be reduced to,\n", + "$$ \n", + "\\begin{equation}\n", + "H_{(U, V)} = U (Z_0 Z_2 - 1) / 4 + V (X_0 + X_2),\n", + "\\end{equation}\n", + "$$\n", + "where $U$ is the Coulomb interaction and $V$ the hybridization strength. In this notebook workflow, we will optimize over a 2-dimensional grid of Hamiltonian parameter values, namely $U\\in \\{1, 5, 9\\}$ and $V\\in \\{-9, -1, 7\\}$ (with all values assumed to be in units of eV), to ensure that the ansatz is generally trainable and expressive, and obtain 9 different circuit layers identified by the key $(U, V)$. We will simulate the VQE on GPU (or optionally on CPU if you do not have GPU access), enabled by CUDA-Q, in the absence of noise:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "if cudaq.num_available_gpus() == 0:\n", + " cudaq.set_target(\"qpp-cpu\", option=\"fp64\")\n", + "else:\n", + " cudaq.set_target(\"nvidia\", option=\"fp64\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This workflow can be easily defined in CUDA-Q as shown in the cell below, using the CUDA-QX Solvers library (which accelerates quantum algorithms like the VQE):" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def ansatz(n_qubits: int) -> cudaq.Kernel:\n", + " # Create a CUDA-Q parameterized kernel\n", + " paramterized_ansatz, variational_angles = cudaq.make_kernel(list)\n", + " qubits = paramterized_ansatz.qalloc(n_qubits)\n", + "\n", + " # Using |+> as the initial state:\n", + " paramterized_ansatz.h(qubits[0])\n", + " paramterized_ansatz.cx(qubits[0], qubits[1])\n", + "\n", + " paramterized_ansatz.rx(variational_angles[0], qubits[0])\n", + " paramterized_ansatz.cx(qubits[0], qubits[1])\n", + " paramterized_ansatz.rz(variational_angles[1], qubits[1])\n", + " paramterized_ansatz.cx(qubits[0], qubits[1])\n", + " return paramterized_ansatz\n", + "\n", + "\n", + "def run_logical_vqe(cudaq_hamiltonian: cudaq.SpinOperator) -> tuple[float, list[float]]:\n", + " # Set seed for easier reproduction\n", + " np.random.seed(42)\n", + "\n", + " # Initial angles for the optimizer\n", + " init_angles = np.random.random(2) * 1e-1\n", + "\n", + " # Obtain CUDA-Q Ansatz\n", + " num_qubits = cudaq_hamiltonian.get_qubit_count()\n", + " variational_kernel = ansatz(num_qubits)\n", + "\n", + " # Perform VQE optimization\n", + " energy, params, _ = solvers.vqe(\n", + " variational_kernel,\n", + " cudaq_hamiltonian,\n", + " init_angles,\n", + " optimizer=minimize,\n", + " method=\"SLSQP\",\n", + " tol=1e-10,\n", + " )\n", + " return energy, params" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constructing circuits in the `[[4,2,2]]` encoding" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `[[4,2,2]]` code is a quantum error detection code that uses four physical qubits to encode two logical qubits. In this notebook, we will construct two variants of quantum circuits: physical (bare, unencoded) and logical (encoded). These circuits will be informed by the Hamiltonian Variational Ansatz described earlier. To measure all the terms in our Hamiltonian, we will measure the data qubits in both the $Z$- and $X$-basis, as allowed by the `[[4,2,2]]` logical gateset. Full details on the circuit constructions are outlined in our [paper](https://arxiv.org/abs/2412.07670)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below, we create functions to build our CUDA-Q AIM circuits, both physical and logical versions. As we consider noisy simulation in this notebook, we will include some noisy gates. Here, for simplicity, we will just register a custom identity gate -- to be later used as a noisy operation to model readout error: " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "cudaq.register_operation(\"meas_id\", np.identity(2))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def aim_physical_circuit(\n", + " angles: list[float], basis: str, *, ignore_meas_id: bool = False\n", + ") -> cudaq.Kernel:\n", + " kernel = cudaq.make_kernel()\n", + " qubits = kernel.qalloc(2)\n", + "\n", + " # Bell state prep\n", + " kernel.h(qubits[0])\n", + " kernel.cx(qubits[0], qubits[1])\n", + "\n", + " # Rx Gate\n", + " kernel.rx(angles[0], qubits[0])\n", + "\n", + " # ZZ rotation\n", + " kernel.cx(qubits[0], qubits[1])\n", + " kernel.rz(angles[1], qubits[1])\n", + " kernel.cx(qubits[0], qubits[1])\n", + "\n", + " if basis == \"z_basis\":\n", + " if not ignore_meas_id:\n", + " kernel.for_loop(\n", + " start=0, stop=2, function=lambda q_idx: getattr(kernel, \"meas_id\")(qubits[q_idx])\n", + " )\n", + " kernel.mz(qubits)\n", + " elif basis == \"x_basis\":\n", + " kernel.h(qubits)\n", + " if not ignore_meas_id:\n", + " kernel.for_loop(\n", + " start=0, stop=2, function=lambda q_idx: getattr(kernel, \"meas_id\")(qubits[q_idx])\n", + " )\n", + " kernel.mz(qubits)\n", + " else:\n", + " raise ValueError(\"Unsupported basis provided:\", basis)\n", + " return kernel" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def aim_logical_circuit(\n", + " angles: list[float], basis: str, *, ignore_meas_id: bool = False\n", + ") -> cudaq.Kernel:\n", + " kernel = cudaq.make_kernel()\n", + " qubits = kernel.qalloc(6)\n", + "\n", + " kernel.for_loop(start=0, stop=3, function=lambda idx: kernel.h(qubits[idx]))\n", + " kernel.cx(qubits[1], qubits[4])\n", + " kernel.cx(qubits[2], qubits[3])\n", + " kernel.cx(qubits[0], qubits[1])\n", + " kernel.cx(qubits[0], qubits[3])\n", + "\n", + " # Rx teleportation\n", + " kernel.rx(angles[0], qubits[0])\n", + "\n", + " kernel.cx(qubits[0], qubits[1])\n", + " kernel.cx(qubits[0], qubits[3])\n", + " kernel.h(qubits[0])\n", + "\n", + " if basis == \"z_basis\":\n", + " if not ignore_meas_id:\n", + " kernel.for_loop(\n", + " start=0, stop=5, function=lambda idx: getattr(kernel, \"meas_id\")(qubits[idx])\n", + " )\n", + " kernel.mz(qubits)\n", + " elif basis == \"x_basis\":\n", + " # ZZ rotation and teleportation\n", + " kernel.cx(qubits[3], qubits[5])\n", + " kernel.cx(qubits[2], qubits[5])\n", + " kernel.rz(angles[1], qubits[5])\n", + " kernel.cx(qubits[1], qubits[5])\n", + " kernel.cx(qubits[4], qubits[5])\n", + " kernel.for_loop(start=1, stop=5, function=lambda idx: kernel.h(qubits[idx]))\n", + " if not ignore_meas_id:\n", + " kernel.for_loop(\n", + " start=0, stop=6, function=lambda idx: getattr(kernel, \"meas_id\")(qubits[idx])\n", + " )\n", + " kernel.mz(qubits)\n", + " else:\n", + " raise ValueError(\"Unsupported basis provided:\", basis)\n", + " return kernel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the circuit definitions above, we can now define a function that automatically runs the VQE and constructs a dictionary containing all the AIM circuits we want to submit to hardware (or noisily simulate):" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_circuit_set(ignore_meas_id: bool = False) -> object:\n", + " u_vals = [1, 5, 9]\n", + " v_vals = [-9, -1, 7]\n", + " circuit_dict = {}\n", + " for u in u_vals:\n", + " for v in v_vals:\n", + " qubit_hamiltonian = (\n", + " 0.25 * u * cudaq.spin.z(0) * cudaq.spin.z(1)\n", + " - 0.25 * u\n", + " + v * cudaq.spin.x(0)\n", + " + v * cudaq.spin.x(1)\n", + " )\n", + " _, opt_params = run_logical_vqe(qubit_hamiltonian)\n", + " angles = [float(angle) for angle in opt_params]\n", + " print(f\"Computed optimal angles={angles} for U={u}, V={v}\")\n", + "\n", + " tmp_physical_dict = {}\n", + " tmp_logical_dict = {}\n", + " for basis in (\"z_basis\", \"x_basis\"):\n", + " tmp_physical_dict[basis] = aim_physical_circuit(\n", + " angles, basis, ignore_meas_id=ignore_meas_id\n", + " )\n", + " tmp_logical_dict[basis] = aim_logical_circuit(\n", + " angles, basis, ignore_meas_id=ignore_meas_id\n", + " )\n", + "\n", + " circuit_dict[f\"{u}:{v}\"] = {\n", + " \"physical\": tmp_physical_dict,\n", + " \"logical\": tmp_logical_dict,\n", + " }\n", + " print(\"\\nFinished building optimized circuits!\")\n", + " return circuit_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Computed optimal angles=[1.5846845738799267, 1.5707961678256028] for U=1, V=-9\n", + "Computed optimal angles=[4.588033710930825, 4.712388365176642] for U=1, V=-1\n", + "Computed optimal angles=[-1.588651490745171, 1.5707962742876598] for U=1, V=7\n", + "Computed optimal angles=[1.64012940802256, 1.5707963354922125] for U=5, V=-9\n", + "Computed optimal angles=[2.1293956916868737, 1.5707963294715355] for U=5, V=-1\n", + "Computed optimal angles=[-1.6598458659836037, 1.570796331040382] for U=5, V=7\n", + "Computed optimal angles=[1.695151467539617, 1.5707960973500679] for U=9, V=-9\n", + "Computed optimal angles=[2.4149519241823376, 1.5707928509325972] for U=9, V=-1\n", + "Computed optimal angles=[-1.7301462729177735, 1.570796033796985] for U=9, V=7\n", + "\n", + "Finished building optimized circuits!\n" + ] + } + ], + "source": [ + "sim_circuit_dict = generate_circuit_set()\n", + "circuit_layers = sim_circuit_dict.keys()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting up submission and decoding workflow " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section, we define various helper functions that will play a role in generating the associated energies of the AIM circuits based on the circuit samples (in the different bases), as well as decode the logical circuits with post-selection informed by the `[[4,2,2]]` code:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def _num_qubits(counts: Mapping[str, float]) -> int:\n", + " for key in counts:\n", + " if key.isdecimal():\n", + " return len(key)\n", + " return 0\n", + "\n", + "\n", + "def process_counts(\n", + " counts: Mapping[str, float],\n", + " data_qubits: Sequence[int],\n", + " flag_qubits: Sequence[int] = (),\n", + ") -> dict[str, float]:\n", + " new_data: dict[str, float] = {}\n", + " for key, val in counts.items():\n", + " if not all(key[i] == \"0\" for i in flag_qubits):\n", + " continue\n", + "\n", + " new_key = \"\".join(key[i] for i in data_qubits)\n", + "\n", + " if not set(\"01\").issuperset(new_key):\n", + " continue\n", + "\n", + " new_data.setdefault(new_key, 0)\n", + " new_data[new_key] += val\n", + "\n", + " return new_data\n", + "\n", + "\n", + "def decode(counts: Mapping[str, float]) -> dict[str, float]:\n", + " \"\"\"Decode physical counts into logical counts. Should be called after `process_counts`.\"\"\"\n", + "\n", + " if not counts:\n", + " return {}\n", + "\n", + " num_qubits = _num_qubits(counts)\n", + " assert num_qubits % 4 == 0\n", + "\n", + " physical_to_logical = {\n", + " \"0000\": \"00\",\n", + " \"1111\": \"00\",\n", + " \"0011\": \"01\",\n", + " \"1100\": \"01\",\n", + " \"0101\": \"10\",\n", + " \"1010\": \"10\",\n", + " \"0110\": \"11\",\n", + " \"1001\": \"11\",\n", + " }\n", + "\n", + " new_data: dict[str, float] = {}\n", + " for key, val in counts.items():\n", + " physical_keys = [key[i : i + 4] for i in range(0, num_qubits, 4)]\n", + " logical_keys = [physical_to_logical.get(physical_key) for physical_key in physical_keys]\n", + " if None not in logical_keys:\n", + " new_key = \"\".join(logical_keys)\n", + " new_data.setdefault(new_key, 0)\n", + " new_data[new_key] += val\n", + "\n", + " return new_data\n", + "\n", + "\n", + "def ev_x(counts: Mapping[str, float]) -> float:\n", + " ev = 0.0\n", + "\n", + " for k, val in counts.items():\n", + " ev += val * ((-1) ** int(k[0]) + (-1) ** int(k[1]))\n", + "\n", + " total = sum(counts.values())\n", + " ev /= total\n", + " return ev\n", + "\n", + "\n", + "def ev_xx(counts: Mapping[str, float]) -> float:\n", + " ev = 0.0\n", + "\n", + " for k, val in counts.items():\n", + " ev += val * (-1) ** k.count(\"1\")\n", + "\n", + " total = sum(counts.values())\n", + " ev /= total\n", + " return ev\n", + "\n", + "\n", + "def ev_zz(counts: Mapping[str, float]) -> float:\n", + " ev = 0.0\n", + "\n", + " for k, val in counts.items():\n", + " ev += val * (-1) ** k.count(\"1\")\n", + "\n", + " total = sum(counts.values())\n", + " ev /= total\n", + " return ev\n", + "\n", + "\n", + "def aim_logical_energies(\n", + " data_ordering: object, counts_list: Sequence[dict[str, float]]\n", + ") -> tuple[dict[tuple[int, int], float], dict[tuple[int, int], float]]:\n", + " counts_data = {\n", + " data_ordering[i]: decode(\n", + " process_counts(\n", + " counts,\n", + " data_qubits=[1, 2, 3, 4],\n", + " flag_qubits=[0, 5],\n", + " )\n", + " )\n", + " for i, counts in enumerate(counts_list)\n", + " }\n", + " return _aim_energies(counts_data)\n", + "\n", + "\n", + "def aim_physical_energies(\n", + " data_ordering: object, counts_list: Sequence[dict[str, float]]\n", + ") -> tuple[dict[tuple[int, int], float], dict[tuple[int, int], float]]:\n", + " counts_data = {\n", + " data_ordering[i]: process_counts(\n", + " counts,\n", + " data_qubits=[0, 1],\n", + " )\n", + " for i, counts in enumerate(counts_list)\n", + " }\n", + " return _aim_energies(counts_data)\n", + "\n", + "\n", + "def _aim_energies(\n", + " counts_data: Mapping[tuple[int, int, str], dict[str, float]],\n", + ") -> tuple[dict[tuple[int, int], float], dict[tuple[int, int], float]]:\n", + " evxs: dict[tuple[int, int], float] = {}\n", + " evxxs: dict[tuple[int, int], float] = {}\n", + " evzzs: dict[tuple[int, int], float] = {}\n", + " totals: dict[tuple[int, int], float] = {}\n", + "\n", + " for key, counts in counts_data.items():\n", + " h_params, basis = key\n", + " key_a, key_b = h_params.split(\":\")\n", + " u, v = int(key_a), int(key_b)\n", + " if basis.startswith(\"x\"):\n", + " evxs[u, v] = ev_x(counts)\n", + " evxxs[u, v] = ev_xx(counts)\n", + " else:\n", + " evzzs[u, v] = ev_zz(counts)\n", + "\n", + " totals.setdefault((u, v), 0)\n", + " totals[u, v] += sum(counts.values())\n", + "\n", + " energies = {}\n", + " uncertainties = {}\n", + " for u, v in evxs.keys() & evzzs.keys():\n", + " string_key = f\"{u}:{v}\"\n", + " energies[string_key] = u * (evzzs[u, v] - 1) / 4 + v * evxs[u, v]\n", + "\n", + " uncertainty_xx = 2 * v**2 * (1 + evxxs[u, v]) - u * v * evxs[u, v] / 2\n", + " uncertainty_zz = u**2 * (1 - evzzs[u, v]) / 2\n", + "\n", + " uncertainties[string_key] = np.sqrt(\n", + " (uncertainty_zz + uncertainty_xx - energies[string_key] ** 2) / (totals[u, v] / 2)\n", + " )\n", + "\n", + " return energies, uncertainties\n", + "\n", + "\n", + "def _get_energy_diff(\n", + " bf_energies: dict[str, float],\n", + " physical_energies: dict[str, float],\n", + " logical_energies: dict[str, float],\n", + ") -> tuple[list[float], list[float]]:\n", + " physical_energy_diff = []\n", + " logical_energy_diff = []\n", + "\n", + " # Data ordering following `bf_energies` keys\n", + " for layer in bf_energies.keys():\n", + " physical_sim_energy = physical_energies[layer]\n", + " logical_sim_energy = logical_energies[layer]\n", + " true_energy = bf_energies[layer]\n", + " u, v = layer.split(\":\")\n", + " print(f\"Layer=({u}, {v}) has brute-force energy of: {true_energy}\")\n", + " print(f\"Physical circuit of layer=({u}, {v}) got an energy of: {physical_sim_energy}\")\n", + " print(f\"Logical circuit of layer=({u}, {v}) got an energy of: {logical_sim_energy}\")\n", + " print(\"-\" * 72)\n", + "\n", + " if logical_sim_energy < physical_sim_energy:\n", + " print(\"Logical circuit achieved the lower energy!\")\n", + " else:\n", + " print(\"Physical circuit achieved the lower energy\")\n", + " print(\"-\" * 72, \"\\n\")\n", + "\n", + " physical_energy_diff.append(\n", + " -1 * (true_energy - physical_sim_energy)\n", + " ) # Multiply by -1 since negative energies\n", + " logical_energy_diff.append(-1 * (true_energy - logical_sim_energy))\n", + " return physical_energy_diff, logical_energy_diff" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def submit_aim_circuits(\n", + " circuit_dict: object,\n", + " *,\n", + " folder_path: str = \"future_aim_results\",\n", + " shots_count: int = 1000,\n", + " noise_model: cudaq.mlir._mlir_libs._quakeDialects.cudaq_runtime.NoiseModel | None = None,\n", + " run_async: bool = False,\n", + ") -> dict[str, list[dict[str, int]]] | None:\n", + " if run_async:\n", + " os.makedirs(folder_path, exist_ok=True)\n", + " else:\n", + " aim_results = {\"physical\": [], \"logical\": []}\n", + "\n", + " for layer in circuit_dict.keys():\n", + " if run_async:\n", + " print(f\"Posting circuits associated with layer=('{layer}')\")\n", + " else:\n", + " print(f\"Running circuits associated with layer=('{layer}')\")\n", + "\n", + " for basis in (\"z_basis\", \"x_basis\"):\n", + " if run_async:\n", + " u, v = layer.split(\":\")\n", + "\n", + " tmp_physical_results = cudaq.sample_async(\n", + " circuit_dict[layer][\"physical\"][basis], shots_count=shots_count\n", + " )\n", + " file = open(f\"{folder_path}/physical_{basis}_job_u={u}_v={v}_result.txt\", \"w\")\n", + " file.write(str(tmp_physical_results))\n", + " file.close()\n", + "\n", + " tmp_logical_results = cudaq.sample_async(\n", + " circuit_dict[layer][\"logical\"][basis], shots_count=shots_count\n", + " )\n", + " file = open(f\"{folder_path}/logical_{basis}_job_u={u}_v={v}_result.txt\", \"w\")\n", + " file.write(str(tmp_logical_results))\n", + " file.close()\n", + " else:\n", + " tmp_physical_results = cudaq.sample(\n", + " circuit_dict[layer][\"physical\"][basis],\n", + " shots_count=shots_count,\n", + " noise_model=noise_model,\n", + " )\n", + " tmp_logical_results = cudaq.sample(\n", + " circuit_dict[layer][\"logical\"][basis],\n", + " shots_count=shots_count,\n", + " noise_model=noise_model,\n", + " )\n", + " aim_results[\"physical\"].append({k: v for k, v in tmp_physical_results.items()})\n", + " aim_results[\"logical\"].append({k: v for k, v in tmp_logical_results.items()})\n", + " if not run_async:\n", + " print(\"\\nCompleted all circuit sampling!\")\n", + " return aim_results\n", + " else:\n", + " print(\"\\nAll circuits submitted for async sampling!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def _get_async_results(\n", + " layers: object, *, folder_path: str = \"future_aim_results\"\n", + ") -> dict[str, list[dict[str, int]]]:\n", + " aim_results = {\"physical\": [], \"logical\": []}\n", + " for layer in layers:\n", + " print(f\"Retrieving all circuits counts associated with layer=('{layer}')\")\n", + " u, v = layer.split(\":\")\n", + " for basis in (\"z_basis\", \"x_basis\"):\n", + " file = open(f\"{folder_path}/physical_{basis}_job_u={u}_v={v}_result.txt\", \"r\")\n", + " tmp_physical_results = cudaq.AsyncSampleResult(str(file.read()))\n", + " physical_counts = tmp_physical_results.get()\n", + "\n", + " file = open(f\"{folder_path}/logical_{basis}_job_u={u}_v={v}_result.txt\", \"r\")\n", + " tmp_logical_results = cudaq.AsyncSampleResult(str(file.read()))\n", + " logical_counts = tmp_logical_results.get()\n", + "\n", + " aim_results[\"physical\"].append({k: v for k, v in physical_counts.items()})\n", + " aim_results[\"logical\"].append({k: v for k, v in logical_counts.items()})\n", + "\n", + " print(\"\\nObtained all circuit samples!\")\n", + " return aim_results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running a CUDA-Q noisy simulation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section, we will first explore the performance of the physical and logical circuits under the influence of a device noise model. This will help us predict experimental results, as well as understand the dominant error sources at play. Such a simulation can be achieved via CUDA-Q's density matrix simulator: " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "cudaq.reset_target()\n", + "cudaq.set_target(\"density-matrix-cpu\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def get_device_noise(\n", + " depolar_prob_1q: float,\n", + " depolar_prob_2q: float,\n", + " *,\n", + " readout_error_prob: float | None = None,\n", + " custom_gates: list[str] | None = None,\n", + ") -> cudaq.mlir._mlir_libs._quakeDialects.cudaq_runtime.NoiseModel:\n", + " noise = cudaq.NoiseModel()\n", + " depolar_noise = cudaq.DepolarizationChannel(depolar_prob_1q)\n", + "\n", + " noisy_ops = [\"z\", \"s\", \"x\", \"h\", \"rx\", \"rz\"]\n", + " for op in noisy_ops:\n", + " noise.add_all_qubit_channel(op, depolar_noise)\n", + "\n", + " if custom_gates:\n", + " custom_depolar_channel = cudaq.DepolarizationChannel(depolar_prob_1q)\n", + " for op in custom_gates:\n", + " noise.add_all_qubit_channel(op, custom_depolar_channel)\n", + "\n", + " # Two qubit depolarization error\n", + " p_0 = 1 - depolar_prob_2q\n", + " p_1 = np.sqrt((1 - p_0**2) / 3)\n", + "\n", + " k0 = np.array(\n", + " [[p_0, 0.0, 0.0, 0.0], [0.0, p_0, 0.0, 0.0], [0.0, 0.0, p_0, 0.0], [0.0, 0.0, 0.0, p_0]],\n", + " dtype=np.complex128,\n", + " )\n", + " k1 = np.array(\n", + " [[0.0, 0.0, p_1, 0.0], [0.0, 0.0, 0.0, p_1], [p_1, 0.0, 0.0, 0.0], [0.0, p_1, 0.0, 0.0]],\n", + " dtype=np.complex128,\n", + " )\n", + " k2 = np.array(\n", + " [\n", + " [0.0, 0.0, -1j * p_1, 0.0],\n", + " [0.0, 0.0, 0.0, -1j * p_1],\n", + " [1j * p_1, 0.0, 0.0, 0.0],\n", + " [0.0, 1j * p_1, 0.0, 0.0],\n", + " ],\n", + " dtype=np.complex128,\n", + " )\n", + " k3 = np.array(\n", + " [[p_1, 0.0, 0.0, 0.0], [0.0, p_1, 0.0, 0.0], [0.0, 0.0, -p_1, 0.0], [0.0, 0.0, 0.0, -p_1]],\n", + " dtype=np.complex128,\n", + " )\n", + " kraus_channel = cudaq.KrausChannel([k0, k1, k2, k3])\n", + "\n", + " noise.add_all_qubit_channel(\"cz\", kraus_channel)\n", + " noise.add_all_qubit_channel(\"cx\", kraus_channel)\n", + "\n", + " if readout_error_prob is not None:\n", + " # Readout error modeled with a Bit flip channel on identity before measurement\n", + " bit_flip = cudaq.BitFlipChannel(readout_error_prob)\n", + " noise.add_all_qubit_channel(\"meas_id\", bit_flip)\n", + " return noise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, with our example noise model defined above, we can synchronously & noisily sample all of our AIM circuits by passing `noise_model=cudaq_noise_model` to the workflow containing function `submit_aim_circuits()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# Example parameters that can model execution on hardware at the high, simulation, level:\n", + "# Take single-qubit gate depolarization rate: ~0.2% or better (fidelity ≥99.8%)\n", + "# Take two-qubit gate depolarization rate: ~1–2% (fidelity ~98–99%)\n", + "cudaq_noise_model = get_device_noise(0.002, 0.02, readout_error_prob=0.02)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running circuits associated with layer=('1:-9')\n", + "Running circuits associated with layer=('1:-1')\n", + "Running circuits associated with layer=('1:7')\n", + "Running circuits associated with layer=('5:-9')\n", + "Running circuits associated with layer=('5:-1')\n", + "Running circuits associated with layer=('5:7')\n", + "Running circuits associated with layer=('9:-9')\n", + "Running circuits associated with layer=('9:-1')\n", + "Running circuits associated with layer=('9:7')\n", + "\n", + "Completed all circuit sampling!\n" + ] + } + ], + "source": [ + "aim_sim_data = submit_aim_circuits(sim_circuit_dict, noise_model=cudaq_noise_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "data_ordering = []\n", + "for key in circuit_layers:\n", + " for basis in (\"z_basis\", \"x_basis\"):\n", + " data_ordering.append((key, basis))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "sim_physical_energies, sim_physical_uncertainties = aim_physical_energies(\n", + " data_ordering, aim_sim_data[\"physical\"]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "sim_logical_energies, sim_logical_uncertainties = aim_logical_energies(\n", + " data_ordering, aim_sim_data[\"logical\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To analyze our simulated energy results in the above cells, we will compare them to the brute-force computed exact ground state energies for the AIM Hamiltonian. For simplicity, these are already stored in the dictionary `bf_energies` below:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "bf_energies = {\n", + " \"1:-9\": -18.251736027394713,\n", + " \"1:-1\": -2.265564437074638,\n", + " \"1:7\": -14.252231964940428,\n", + " \"5:-9\": -19.293350575766127,\n", + " \"5:-1\": -3.608495283014149,\n", + " \"5:7\": -15.305692796870582,\n", + " \"9:-9\": -20.39007993367173,\n", + " \"9:-1\": -5.260398644698076,\n", + " \"9:7\": -16.429650912487233,\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the above metric, we can assess the performance of the logical circuits against the physical circuits by considering how far away the respective energies are from the brute-force expected energies. The cell below computes these energy deviations:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Layer=(1, -9) has brute-force energy of: -18.251736027394713\n", + "Physical circuit of layer=(1, -9) got an energy of: -15.929\n", + "Logical circuit of layer=(1, -9) got an energy of: -17.46016175277361\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(1, -1) has brute-force energy of: -2.265564437074638\n", + "Physical circuit of layer=(1, -1) got an energy of: -1.97\n", + "Logical circuit of layer=(1, -1) got an energy of: -2.176531948420889\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(1, 7) has brute-force energy of: -14.252231964940428\n", + "Physical circuit of layer=(1, 7) got an energy of: -12.268\n", + "Logical circuit of layer=(1, 7) got an energy of: -13.26321740664324\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, -9) has brute-force energy of: -19.293350575766127\n", + "Physical circuit of layer=(5, -9) got an energy of: -16.8495\n", + "Logical circuit of layer=(5, -9) got an energy of: -18.46681284816878\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, -1) has brute-force energy of: -3.608495283014149\n", + "Physical circuit of layer=(5, -1) got an energy of: -3.1965000000000003\n", + "Logical circuit of layer=(5, -1) got an energy of: -3.4531715120183297\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, 7) has brute-force energy of: -15.305692796870582\n", + "Physical circuit of layer=(5, 7) got an energy of: -13.336\n", + "Logical circuit of layer=(5, 7) got an energy of: -14.341784541550897\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, -9) has brute-force energy of: -20.39007993367173\n", + "Physical circuit of layer=(9, -9) got an energy of: -17.802\n", + "Logical circuit of layer=(9, -9) got an energy of: -19.339249509416753\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, -1) has brute-force energy of: -5.260398644698076\n", + "Physical circuit of layer=(9, -1) got an energy of: -4.8580000000000005\n", + "Logical circuit of layer=(9, -1) got an energy of: -5.1227150992242025\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, 7) has brute-force energy of: -16.429650912487233\n", + "Physical circuit of layer=(9, 7) got an energy of: -14.3635\n", + "Logical circuit of layer=(9, 7) got an energy of: -15.448422736181264\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n" + ] + } + ], + "source": [ + "sim_physical_energy_diff, sim_logical_energy_diff = _get_energy_diff(\n", + " bf_energies, sim_physical_energies, sim_logical_energies\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both physical and logical circuits were subject to the same noise model, but the `[[4,2,2]]` provides additional information that can help overcome some errors. Visualizing the computed energy differences from the above the cell, our noisy simulation provides a preview of the benefits logical qubits can offer:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAACIMAAAVkCAYAAABNJ02+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAB7CAAAewgFu0HU+AAEAAElEQVR4nOzdd1RU1/c28GfovWNXsBCxKwhWBLEbe+81tqgxliTGxBLLV41Go9FYE3vXqLFrFDv2ggVsoGKnd6n3/cNXfg73DkxlAJ/PWq7l7Ln3nM30mbvvPjJBEAQQERERERERERERERERERERUZFgoO8EiIiIiIiIiIiIiIiIiIiIiEh7WAxCREREREREREREREREREREVISwGISIiIiIiIiIiIiIiIiIiIioCGExCBEREREREREREREREREREVERwmIQIiIiIiIiIiIiIiIiIiIioiKExSBERERERERERERERERERERERQiLQYiIiIiIiIiIiIiIiIiIiIiKEBaDEBERERERERERERERERERERUhLAYhIiIiIiIiIiIiIiIiIiIiKkJYDEJERERERERERERERERERERUhLAYhIiIiIiIiIiIiIiIiIiIiKgIYTEIERERERERERERERERERERURHCYhAiIiIiIiIiIiIiIiIiIiKiIoTFIERERERERERERERERERERERFCItBiIiIiIiIiIiIiIiIiIiIiIoQFoMQERERERERERERERERERERFSEsBiEiIiIiIiIiIiIiIiIiIiIqQlgMQkRERERERERERERERERERFSEsBiEiIiIiIiIiIiIiIiIiIiIqAhhMQgRERERERERERERERERERFREcJiECIiIiIios/IjBkzIJPJ5P7NmDFD32kRAD8/P9F9c/r0aX2nRVrA513B5+rqKrqPnj59qu+0CgQ+fgufsLAwmJuby91np06dUmpfvhdRQbd+/XrRY3TQoEH6Tkvn+FpMhUGTJk3kHqNfffWVvlMiIvrsGek7ASIiIso/oaGhePLkCZ4/f474+HgkJyfDxMQEdnZ2sLe3R/HixVGrVi3Y2NjoO1WiXCUmJuLevXsIDQ1FREQEkpKSIAgCLC0t4ezsjIoVK6Jq1aqwtrbWd6pESktMTERwcDCePXuGN2/eIDk5Genp6bCxsYG9vT3s7OzwxRdfwM3NDTKZTN/pEhV6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f+kxIyIi+tykpaVh0aJFcrE+ffqwEISISE9YDEJERERERdLEiRMxfvx4UTwyMhItW7bEixcv9JAVEREREZFuuLm5YdiwYXKxBQsWiJZPJCIi0pV169bh1atX2ZfNzMwwc+ZMPWZERPR5YzEIERERERVZv/32G3r16iWKP3/+HK1atUJ0dLQesiIiIiIi0o3Zs2fD0dEx+/Lz58+xfPlyPWZERESfi6SkJPzyyy9yse+//x7ly5fXU0ZERMRiECIiIiIqsmQyGTZs2AB/f3/Rdffv38eXX36J5ORkPWRGRERERKR9Dg4OmDt3rlxszpw5iIuL01NGRET0uVi0aBFev36dfdnV1RWTJ0/WY0ZERCQTBEHQdxJERERERLoUHx+P4cOHIzY2VnRdmzZtMG7cuPxPioiIiIhIB7KysrBgwQKkpKRkxzp06AAPDw89ZkVEREXdokWLEB8fn325RYsWaNSokR4zIiIiFoMQERERERERERERERERERERFSFcJoaIiIiIiIiIiIiIiIiIiIioCGExCBEREREREREREREREREREVERwmIQIiIiIiIiIiIiIiIiIiIioiKExSBERERERERERERERERERERERQiLQYiIiIiIiIiIiIiIiIiIiIiKECN9J0CkyPv373Hnzh0AgLOzM4yM+HAlIiIiIiIiIiIiIiIiIqKiJSMjAxEREQCAGjVqwMzMTOMxeXSdCqw7d+7A29tb32kQERERERERERERERERERHliytXrsDLy0vjcbhMDBEREREREREREREREREREVERws4gVGA5Oztn///KlSsoWbKkHrMhIiIiIiIiIiIiIiIiIiLSvtevX2evmvHpcXJNsBiECiwjo/97eJYsWRJlypTRYzZERERERERERERERERERES69elxck1wmRgiIiIiIiIiIiIiIiIiIiKiIoTFIERERERERERERERERERERERFCItBiIiIiIiIiIiIiIiIiIiIiIoQFoMQERERERERERERERERERERFSEsBiEiIiIiIiIiIiIiIiIiIiIqQlgMQkRERERERERERERERERERFSEsBiEiIiIiIiIiIiIiIiIiIiIqAgx0ncCRVlUVBQePnyI8PBwvH37FklJScjKyoKtrS2cnJxQq1YtVK5cGTKZTN+pAgAiIiIQGBiI0NBQJCYmwsLCAi4uLvD29kbZsmX1nR4REREREREREREREREREREpgcUgWnT79m0cOnQIFy5cwM2bN/H69es897Gzs0OvXr0watQo1KxZMx+yFDt79ixmz56NkydPIisrS3Kb+vXrY/LkyejYsWM+Z0dERERERERERERERERERESqkAmCIOg7iaKiX79+2LJli1r7GhgYYMyYMZg3bx7Mzc21nJm0jIwMTJgwAX/88YfS+/To0QN///03LC0tdZjZBy9evMjuSBIeHo4yZcrofE4iIiIiIiIiIiIiIiIiIqL8pItj4wYaj0BKMTExgaOjI6ysrCSXhcnKysLSpUvRpk0bJCYm6jyfrKws9O3bV2EhiK2trWR8586daNu2Ld6/f6/L9IiIiIiIiIiIiIiIiIiIiEhNLAbRgRIlSqBXr15YsWIFAgMDER0djdTUVERGRiIhIQGJiYm4cOECxo0bJ+oCcubMGYwYMULnOc6dOxc7d+6Ui9WoUQM7d+5EQkICYmNjkZycjMOHD6NRo0Zy2509exbffPONznMkIiIiIiIiIiIiIiIiIiIi1XGZGC3at28fnJ2d0bBhQ8nuH1KePHmC1q1b4/Hjx3Lxs2fPwsfHRxdpIjw8HG5ubkhNTc2OtWzZEnv37oWFhYVo+4yMDAwdOhQbN26Ui1+5cgVeXl46yRHgMjFERERERERERERERERERFT0cZmYAq5Tp05o1KiR0oUgAFCxYkUcPHgQJiYmcvFNmzZpO71ss2bNkisEKVmyJHbs2CFZCAIARkZGWLt2LapXry4X//nnn3WWIxEREREREREREREREREREamHxSAFQOXKldGhQwe52JkzZ3QyV0REBNatWycXmz17Nuzs7HLdz9jYGL///rtc7Pjx47h165Z2EyQiIiIiIiIiIiIiIiIiIiKNsBikgKhfv77c5VevXulkngMHDiAjIyP7sq2tLXr16qXUvv7+/qhUqZJcbO/evVrNj4iIiIiIiIiIiIiIiIiIiDTDYpACwtraWu5yVlaWTubZv3+/3OV27dopXB4mJ5lMhh49euQ6HhEREREREREREREREREREekXi0EKiJcvX8pdLlu2rE7mCQgIkLvcqFEjlfZv2LCh3OXbt28jKipK47yIiIiIiIiIiIiIiIiIiIhIO1gMUkAcPHhQ7rK/v7/W5wgPD0dCQoJcrF69eiqNkXM5GwAIDg7WKC8iIiIiIiIiIiIiIiIiIiLSHhaDFAArVqzAjRs3si8bGhpizJgxWp8nJCREFKtQoYJKYzg6OsLGxibPcYmIiIiIiIiIiIiIiIiIiEg/WAyiR4mJiZg6daqo8GP69OmoWrWq1ud7+PCh3GVra2vY2dmpPE7OJWwePHigSVpERERERERERERERERERESkRUb6TqAoEwQBq1atkoulpqYiKioKQUFB+O+//5CUlJR9nYGBAX766SdMnTpVJ/lER0fLXS5RooRa45QsWRL37t3LvhwTE6NRXkRERERERERERERERAWNIAh4//494uLikJqaiszMTGRmZuo7LSIi0jJDQ0MYGhrC1NQUtra2MDMzg0wm03daGmMxiA5lZmZi1KhReW5nZGSENm3a4Oeff4a3t7fO8klMTJS7bGFhodY45ubmuY5LRERERERERERERERUWGVkZCA2NhZxcXFIS0vTdzpERKRjGRkZAIDk5GTExMTAxMQEtra2sLOzg5FR4S2pKLyZFyGNGzdG165dUatWLZ3O82kXEgAwMzNTa5ycxSA5x1XWixcvcr3+9evXao1LRERERERERERERESkjvT0dDx79gzp6emi62QyGQwNDfWQFRER6VJmZiYEQci+nJaWhoiICMTGxsLFxQXGxsZ6zE59LAYpAE6fPo3Tp0/jxx9/xJ9//olOnTrpZJ6UlBS5yyYmJmqNY2pqmuu4yipbtqxa+xEREREREREREREREWlbZmYmwsPD5QpBLCwsYGtrC2traxaCEBEVYZmZmUhISEBcXBySk5MBfCgQDA8Ph4uLS6F8DzDQdwJFmZGREQRBkPuXkJCAJ0+eYNeuXejdu7dcQcbr16/RuXNnLFiwQCf55OwEom5rs9TU1FzHJSIiIiIiIiIiIiIiKkyysrIQHh6efQzE2NgYFStWhIuLC+zs7ArlQUAiIlKeoaEh7Ozs4OLigooVK2Z3A0lNTUV4eDiysrL0nKHq2Bkkn1lZWcHKygoVKlRAt27dEBISgt69e+PWrVvZ23z//fdwd3dH+/bttT73p96/f6/WODk7geQcV1nh4eG5Xv/69Wt4e3urNTYREREREREREREREZGyYmJiso9/GBoaoly5cmp3WCciosLNxMQE5cqVw9OnT5GZmYmUlBTExMTA0dFR36mphMUgeubu7o5Tp06hQYMGePDgQXZ87NixaNu2rVYrTXMWbXxsb6MqbRWDlClTRq39iIiIiIiIiIiIiIiItCkhISH7/2XKlGEhCBHRZ87ExARlypTBs2fPAACJiYmFrhiEy8QUAPb29vjjjz/kYs+ePcPhw4e1Ps+n3r59q9Y4r1+/znVcIiIiIiIiIiIiIiKiwiIjIyP7RFgTExNYWFjoOSMiIioILCwssosDk5OTkZmZqeeMVMNikAKiefPmKFWqlFwsICBAq3N88cUXcpfj4+MRGxur8jg5l3fJOS4REREREREREREREVFhkZSUlP1/a2trPWZCREQFzafvC4mJiXrMRHUsBikgZDIZateuLRcLCwvT6hzu7u6iWGhoqEpjREdHIz4+Ps9xiYiIiIiIiIiIiIiICoNPD+5ZWVnpMRMiIipoPn1fYDEIqc3W1lbucnJyslbHL1u2rOhDzOXLl1Ua49KlS6JYlSpVNMqLiIiIiIiIiIiIiIhIX9LT07P/b25ursdMiIiooPn0feHT94vCgMUgBUhUVJTcZWdnZ62OL5PJ0LRpU7nYhQsXVBoj5/Y1a9aEk5OTxrkRERERERERERERERHpQ1ZWFgDAwMAAMplMz9kQEVFBIpPJst8bPr5fFBYsBikgsrKycOPGDblYqVKltD5Px44d5S4fPHhQpQ4kO3fuzHU8IiIiIiIiIiIiIiKiwiQzMxPAh2IQIiKinAwNDQH83/tFYcF3tQLi4MGDiIyMlIs1b95c6/O0b98eRkZG2Zfj4uKwfft2pfY9deoUHj9+LBfr1KmTNtMjIiIiIiIiIiIiIiIiIiIiDbEYREtSU1PV3jciIgLjx4+Xizk4OMDPzy/X/VxdXbPb0shksjy3B4BixYph4MCBcrGff/4ZsbGxue6Xnp6Ob7/9Vi7WvHlzeHh45DknERERERERERERERERERER5R8Wg2jJ2LFjMXr0aDx//lyl/W7dugU/Pz+EhobKxWfOnAkTExNtppht2rRpcmO/fv0avXr1UrhcTEZGBoYNG4Y7d+7IxWfPnq2T/IiIiIiIiIiIiIiIiIiIiEh9RnlvQspIS0vDmjVrsGLFCjRq1AgdO3aEp6cnatasCUdHx+ztBEHA06dPcfXqVezYsQP79+8XrS3k7++PkSNH6izXcuXK4aeffsL06dOzY8eOHUP9+vUxbdo0tGnTBpaWlkhJScHZs2cxa9YsXLhwQW6MIUOGoF69ejrLkYiIiIiIiIiIiIiIiHRnxaqjWLH6qNbHHTW8NUaNaK31cYmISDUsBtEyQRBw/vx5nD9/PjtmaGgIGxsbZGVlISEhAVlZWQr3b9q0KQ4cOABDQ0Od5vnzzz/jzp072L17d3bszp076N69OwDA1tYW8fHxEARBtG/jxo2xbNkyneZHREREREREREREREREupOQmILXb2J0Mi4REekfi0HyQWZmJmJicn8ztbCwwC+//ILx48frvBAEAAwMDLB161YUK1YMf/75p+j6uLg4yf26du2K9evXw9zcXNcpEhERERERERERERERkY5YW5mjZAl7hddnZQl4+y5WLla8mB0MDGR5jktERPrHYhAtWbx4MVq3bo2jR4/iwoULePz4cZ77GBoaonbt2ujXrx/69esHJyenfMj0/xgbG2P58uXo3r07Zs+ejVOnTkl2AgEAb29vTJ48GZ07d87XHImIiIiIiIiIiIiIiEj7Ro3IfTmXyKh4VKk5Vi52+r9ZcHK00XVqRESkBSwG0RJ7e3v06tULvXr1AgDExMQgODgYz549w7t375CUlASZTAYbGxvY2tqiYsWKqFWrFiwsLNSe8+nTp1rJ3c/PD35+fnj79i0uXbqE0NBQJCUlwdzcHOXKlUO9evVQrlw5rcxFREREREREREREREREREREusViEB2xt7dHw4YN0bBhQ32norTixYujY8eO+k6DiIiIiIiIiIiIiIiIiIiINGCg7wSIiIiIiIiIiIiIiIiIiKhgWr9+PWQymdy/06dP6zutImfGjBmi21lbK0UUJXw8Ko+dQYiIiIiIiIiIiIiIiIiICjiZTKb0tgYGBrCxsYGdnR2KFSsGT09PeHt7o02bNihevLgOsySigoKdQYiIiIiIiIiIiIiIiIiIipCsrCzExsbi6dOnuHLlClasWIHBgwejXLly6Nu3L+7du6fvFIlIx1gMQkRERERERERERERERET0GUhLS8PWrVvh6emJ33//Xd/pEJEOcZkYIiIiIiIiIiIiIiIiIqJCyNraGgYG4vP/s7KykJCQoHC/1NRUjB8/HpGRkZg9e7YuUyQiPWFnECIiIiIiIiIiIiIiIiKiQigoKAixsbGif/Hx8UhPT0dISAiWLVsGNzc3yf3nzJmDrVu35nPWRJQfWAxCRERERERERERERERERFTEGBkZoXLlyhg9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nBxt9JQRkWJVq1ZFcHBw9mUzMzO8fPkSDg4OWpsjMzMToaGhePz4MV68eIH4+HgkJyfDwsICNjY2KFOmDGrVqoVSpUppbU5tyMrKwu3btxEaGorIyEhERUXByMgI1tbWKF26NKpUqYKKFSvCwED9PhLx8fG4cOECnj17hujoaBgYGMDe3h6VKlWCl5cXbGwK9+tGfrxP6OLYuJHGIxAREREREREREREREREREenBxYsX5QpBAKBr165aLQQBAENDQ7i5uRW6ojEDAwPUqVMHderU0dkcNjY2aNOmjc7GJ/VwmRgiIiIiIiIiIiIiIiIiIiqUVq5cKYoNHz5cD5kQFSwsBiEiIiIiIiIiIiIiIiIiokLn3bt32LVrl1ysevXqaNKkiZ4yIio4WAxCRERERERERERERERERESFzoIFC/D+/Xu52OjRo/WUDVHBwmIQIiIiIiIiIiIiIiIiIiIqVG7evIklS5bIxYoVK4YBAwboKSOigoXFIEREREREREREREREREREVCi8efMGy5YtQ4sWLZCeni533eTJk2FhYaGnzIgKFiN9J0BERERERERERERERJRfVqw6ihWrj2p93FHDW2PUiNZaH5dIV/J6LmRlCaKYX/OpMDCQ5TounwukbVu3bsXXX38NAEhNTRUtC/NR1apVs7cjIhaDEBERERERERERERHRZyQhMQWv38ToZFyiwkSd58Lbd7FKjUukTWlpaYiLi8t1GwsLC2zcuBGmpqb5lBVRwVegikHevn2Lhw8f4unTpwgPD0dCQgKSkpKQkZEBCwsLWFpaolixYnBxcUH58uXh7u4OQ0NDfadNRERERERERERERESFhLWVOUqWsFd4fVaWIDrgXbyYXZ7dEKytzLWRHlG+yeu5oMm4RPmpWLFi2LZtGzw9PfWdClGBotdikMePH+PIkSM4ffo0rl69ipcvX6q0v6mpKWrVqoV69eqhVatW8Pf3Z7UXEREREREREREREREpNGpE7ktYREbFo0rNsXKx0//NgpOjja5TI8pXeT0XiAoqQ0ND2Nvbo2rVqmjfvj2GDh0Ke3vtFzYRFXb5XgwSFhaGjRs3YuvWrXj8+HF2XBDE647l5f3797hy5QquXLmCP/74A2ZmZmjRogUGDBiA9u3bw9jYWJupExERERERERERERERERFRPho0aBAGDRqk7zSICp18KwbZ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+PWvf73OdQMGDIi//vWvOaGIefPmxTPPPLPF71KfvPjii3HUUUfFSy+9tFn3XX/99XHqqafm/LllMpm4+uqr890iAAAAAAAAAFADqY2Jufrqq2Pu3LkREVFUVBS33nprzliXLTFkyJB44IEH4u9//3skSRLXXHNNnH/++dGuXbuc64455pg45JBD4rnnnssee/HFF+Poo4+u0fOrvf766/H666+v99yrr766zrGbb755g7VOPvnkaNGiRV76ivhyZ5Ann3wynnzyyejatWuccMIJ8fWvfz169eoVnTp1iqKioux1n3zySYwaNSr+53/+J9577711al1++eWx33775a03AAAAAAAAAKDmUgmDVFVVxW233RaZTCYiIg444IDo2bNnXmpfcMEF8fe//z0ymUxUVFTEXXfdFRdffPE6151zzjnx3HPPZXsYM2ZMXp4f8eWYmiuvvHKTrz/33HM3eO7II4/MaxhkTZMmTcrZ2SOTycQ222wTJSUlsWDBgqiqqtrgvRdddFFcfvnlBekLAAAAAAAAANhyqYyJef3112P+/PnZ9RFHHJG32gcccEA0bdo0u97Q+JeDDjoo+3WSJDFz5sy89VBfJUkSixcvjvnz528wCNKuXbsYMWJEDB8+vJa7AwAAAAAAAAA2RSphkPfffz8ivgwfRER06tQpb7WLioqiY8eO2frVz1rbdtttF61bt86uy8vL89ZDXdarV6+48cYbY8iQIdG5c+dNuqekpCT69+8ft956a3z22Wdx3HHHFbhLAAAAAAAAAGBLpTImZu7cublNFOe3jUaNGm3wWWtq3bp1NgSyaNGivD3/iiuuiCuuuCJv9b5KdaBmU2277bZx7rnnZkfTzJ8/Pz788MOYNm1azJo1K5YuXRpVVVXRsmXLKCsri5133jn69OkTTZo0KUT7AAAAAAAAAECepRIGWdsXX3yR13prjnzJZDIbvK60tDT7dUlJSV57qC9at24dAwYMSLsNAAAAAAAAACBPUhkTUz3GpTqo8dxzz+Wt9vjx42Px4sXZdYcOHTZ47Zq7gTRv3jxvPQAAAAAAAAAApCWVMMhOO+2U/TpJknjmmWdi2rRpeal96623Zr/OZDI5z1pTVVVVzJ49O7v+qtAIAAAAAAAAAEB9kUoYpH///lFWVpZdr1y5Ms4555xIkqRGdUePHh233HJLZDKZbK2jjjpqvdd+/PHHUVFRERFfhka6dOlSo2cDAAAAAAAAANQFqYRBiouLY/DgwZEkSTa48dRTT8X3v//9bEBjc7388svx7W9/OydQUlRUFCeccMJ6r3/11Vdz1j169Nii5wIAAAAAAAAA1CWphEEiIq644opo3rx5REQ2EHL//ffHXnvtFQ888EBUVlZuUp3JkyfHj3/84zjkkENiwYIFERHZkMm55567wTExjz76aPbaiC93KwEAAAAAAAAAqO8ySU1ns9TADTfcEBdddFFkMpmI+FcwI5PJRFlZWRx66KHRu3fv6NKlS7Rq1SoaN24cixcvjnnz5sW7774bY8aMibFjx2bvXbNOly5d4u23344WLVqs89x58+ZF586do6KiIpIkidLS0pg9e/Z6ryU906dPj86dO0dExLRp06JTp04pdwQAAAAAAAAA+VWIn40X17hCDVx44YUxa9as+N3vfheZTCYnzDF//vx48MEH48EHH/zKGmsGSKrXnTt3jmeffXaD4Y6bb745VqxYkV0feuihgiAAAAAAAAAAQIOQahgkIuI3v/lNtGvXLn7+85/HihUr1gmFbEz1tdXX9+/fP+6+++7o0qXLBu8577zz4t/+7d+y62222WbLXwAAAAAAAAAAoA4pSruBiIiLLroo3nrrrTjiiCMi4stQR/XYl419qq9t3759DBs2LF5++eWvDIJERGy77bax3XbbZT/NmzevhbcEAAAAAAAAACi81HcGqbbbbrvFk08+GRMnTow///nPMWrUqHj77bejsrJyg/d06NAh+vXrFyeddFIcf/zxUVJSUosdAwAAAAAAAADUPXUmDFKtW7du8fvf/z4iIioqKuLDDz+MefPmRXl5eVRUVESrVq2irKwsOnfuHJ07d065WwAAAAAAAACAuqXOhUHWVFpaGl/72tfSbgMAAAAAAAAAoN4oSrsBAAAAAAAAAADyRxgEAAAAAAAAAKABEQYBAAAAAAAAAGhAhEEAAAAAAAAAABoQYRAAAAAAAAAAgAZEGAQAAAAAAAAAoAERBgEAAAAAAAAAaECEQQAAAAAAAAAAGhBhEAAAAAAAAACABkQYBAAAAAAAAACgAREGAQAAAAAAAABoQIRBAAAAAAAAAAAaEGEQAAAAAAAAAIAGRBgEAAAAAAAAAKABEQYBAAAAAAAAAGhAhEEAAAAAAAAAABoQYRAA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CwAAm6qianVB669Yvaqg9QEANpUwCDmmTZsWr732Wnz22WexfPny2GabbaJr167Rv3//aNeuXdrtAQAA9VTLksaxQ5PmGzxflSQxo2JZzrGOpc2iKJPZaF0AANhUpUWNYkUBAyFNGvmxCwBQN/hbSQElSRKffvppjB07NsaNGxdjx46NN998M1asWLHOdWl75JFH4ve//32MGTNmveeLiori0EMPjV/84hdx0EEH1XJ3AABAfbexcS5zKpZH+3/emXPs7YNPiHalTQvdGgAAW5Hdt9k23l40r3D1m7cqWG0AgM0hDJJnS5Ysid/97ncxbty4GDduXCxYsCDtlr7S0qVL44wzzogHHnjgK6+rqqqKkSNHxsiRI+PCCy+Ma6+9NoqL/c8HAAAAAID6o8+2bQsaBumzrR22AYC6wU/z82zu3Lnx29/+Nu02Nsny5cvjqKOOihdffHGdc5lMJlq2bBkLFy5c59wNN9wQs2bNir/97W+R2ciWzQAAAAAAUFcc2b5z3Db1o4LVP6J9p4LVBgDYHEVpN0B6LrzwwnWCIAcccEA89dRTsXTp0liwYEEsWrQo7rvvvth7771zrrvvvvvid7/7XW22CwAAAAAANXJshy7RobRZQWp3KG0Wgzt0KUhtAIDNJQxSYM2bN48DDzwwLr744vjb3/4Wv/71r9NuKSIixo0bF7feemvOsdNPPz2ef/75OOKII6Jp0y/ncrdo0SKGDBkSY8aMicMOOyzn+l/96lcxffr0WusZAAAAAABqonFRoxjatUdBag/t2iNKihoVpDYAwOYyJibPmjVrFuecc07st99+sd9++0X37t2jUaN//eXvjjvuSK+5NVx22WU56x49esQtt9yS0+uamjdvHvfdd1907949Zs6cGRERFRUV8etf/zr+9Kc/FbxfAAAAAADIh6HdesR9X0yM8Qvn5q1mn1Zt4+JuPfNWDwCgpuwMkmft27ePm266Kc4888zo0aPHBsMVaXrzzTdj5MiROceuu+66KCkp+cr7ysrK4r/+679yjt12220xZ86cvPcIAAAAAACFUFLUKO7c55BoWdw4L/VaFTeOO3sPjOIiP3IBAOoOfzPZCj300EM561133TUGDhy4Sfd+97vfjRYtWmTXq1atiscffzyv/QEAAAAAQCHt1bJ1PNlvUI0DIa2KG8c/+g2K7i3K8tQZAEB+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33+sTJ+emzJq06ZNXuvXZ3vssUfOeuHChdnwzKaaPHnyRusCANQVu2+zbWHrN29V0PoAADQslVWr49Q3n6txEKTaolUr4wfjR0VlgXfEAwCgYTFeu+FLJQzSvn37iIjIZDIREfHRRx/ltf5LL72Us873GJr6rHv37usce+211zarxpgxY3LW22yzTXTq1KlGfQEAFEqfbdtu/KIa1W9X0PoAADQswye+u8WjYTZk/MK5MXziu3mtCQBAw2a8dsOXShhk9913z1m/8soreas9a9asePXVV7NBk+Li4thvv/3yVr++a9u2bfTo0SPn2Ob++a99/cCBA7N/3gAAdc2R7TsXtP4R7YViAQDYNCurVsfwSYUJbQyf9K7dQQAA2GTGazd8qYRBdtttt9hpp50iIiJJkhg7dmx8/PHHeak9fPjwWLnyyy0WM5lM7LffftG0adO81G4ojj322Jz1/fffv8n3Llu2LB5//PGvrAcAUJcc26FLdChtVpDaHUqbxeAOXQpSGwCAhueRmVNiZsWygtSeWbEsHp45pSC1AQBoeIzXbvhSCYNERBx55JGRJEl2R4lLLrmkxjVfffXVGD58eGQymUiSJCIEFdbnuOOOy1l/8sknMWrUqE269957741FixZl18XFxfHtb387r/0BAORT46JGMbRrj41fuAWGdu0RJQVO0AMA0HA8NXtaQev/c/b0gtYHAKDhMF674UstDHLxxRdHo0ZffuM8SZJ47LHH4tprr93ieuPGjYvjjz8+Kisrs8datWoV55xzTo17rcsymUzO5/TTT9/oPb17945DDz0059hFF12U82e3PgsWLIjLLrss59jpp58e7du33+y+AQBq09BuPaJ3q/z+46ZPq7Zxcbeeea0JAEDD9saCuQWuP6eg9QEAaDiM1274UguD7LrrrnHaaadldwdJkiQuueSSuPDCC2Pp0qWbXKe8vDyuuOKKOOigg2LWrFnZWplMJi688MJo0aJFAd+i/vrNb36Ts3733Xfj7LPPjtWr1z9XdOnSpXHSSSfFzJkzs8dKS0vjP//zPwvaJwBAPpQUNYo79zkkWhY3zku9VsWN487eA6O4KLW/TgMAUA99tGRBYesvXVjQ+gAANBzGazd8xWk+/Oqrr44XXnghJk2alA1x/M///E/cddddcdJJJ8WAAQNiyZIl2ZEvEREjR46MefPmxWeffRYvvvhivPjii7Fs2bKckTOZTCb69u0bv/jFL1J5r9dffz1ef/319Z579dVX1zl28803b7DWySefXJBAS9++feOMM86I22+/PXvsjjvuiE8//TR++ctfxkEHHRRNmjSJJUuWxJNPPhm/+tWv4r333supcdlll0XnzoVNjAEA5MteLVvHk/0GxaAxT8aiVSu3uE6r4sbxj36DonuLsjx2BwDA1qCiav2/iJUvK1avKmh9AAAajurx2pdOeC3vtY3XrhtSDYO0bt06nnjiiejfv38sWLAgGwhZuHBh/PnPf44///nPOdcnSRJHHnnkOsciIhsESZIkOnToEA888EAUF6fzeo8//nhceeWVm3z9ueeeu8FzRx55ZMF2N/njH/8YH3/8cbzyyivZYy+//HIcccQRkclkomXLlrFw4fp/m+CEE05YZ2QMAEBdN6B1h3j1wMHxg/GjYvzCzd+iu3ertnFX74GCIAAAbJHSokaxooCBkCaNUv12LwAA9czQbj3ivi8mbtH3SjfEeO26I/V9rXfbbbd46aWXYo899sju7lEdCqn+rGnN42teX32uR48e8eqrr8YOO+yQxuvUK82aNYunnnoqjj/++HXOVYdy1ue8886Le+65J4psiw4A1EPdW5TFmAMHx1V79t3kbRA7lDaLq/bsG2MOHCwIAgDAFtt9m20LW795q4LWBwCgYTFeu2GrE/8tdO/ePcaNGxfnnHNOlJSU5IQ8NvaJ+DK40KhRo/jhD38Yo0ePjp122inlN6o/ttlmm/j73/8eI0aMiP3333+D12UymTj00EPj+eefjz/+8Y9RUlJSi10CAORXSVGjuGTXXjH1sO/H/ft+M07eYZd1rtm7RVmcteMecf++34yph30/Ltm1l60NAQCokT7bti1w/XYFrQ8AQMNTPV67poEQ47Xrnkyy9tYbKfviiy9i2LBh8fe//z0+++yzjV7fvn37OOaYY+JnP/tZdO3atRY6bNimTp0aY8aMialTp8aKFSuiefPm0bVr1+jfv3+0b9++VnuZPn16dO7cOSIipk2bFp06darV5wMAW485Fcuj/T/vzDk2+4hTo11p05Q6gq2P/x8CsDV44IuJMeT1ZwpW//59vxknbt+tYPVha+HvpgBsjT5YXG68dooK8bPxOjdEcvvtt48//OEP8Yc//CGmTp0ar7zySkyfPj3m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fp3JZOKAAw7YpPtWrVq10V0+zj333Pjd734XM2bMiCRJ4sYbbxQGYatmnAsAAAAAAADA1qUojYeWl5dHRESSJBERsccee6z3uuqdQ6qtWLFio7WLiori2GOPzdaeMGFCTJ06tSbtAgAAAAAAAADUG6mEQRYsWJCzbtWq1Xqva968eTbUERGxdOnSTaq/995756zfeuutzeoPAAAAAAAAAKC+SiUM0rhx45z1hka/tGjRImc9ffr0Tarfrl27nPVnn322Gd0BAAAAAAAAANRfqYRBWrZsmbNevHjxeq8rKyvLWU+ZMmWT6i9fvjwi/jVmZkP1AQAAAAAAAAAamlTCIDvuuGNE/CusUV5evt7r9txzz5zrXn311U2q/8EHH0REZEfMNG3adMubBQAAAAAAAACoR1IJg+yxxx45648++mi91/Xo0SP7dZIk8fjjj29S/YceeigbIImIaNu27RZ0CQAAAAAAAABQ/6QSBtlpp51yRsBU7+SxtgMPPDBKSkqy608++STuvffer6x90003xccff5xzrFevXlveLAAAAAAAAABAPZJKGCTiy6BHkiSRJEm8/vrrUVFRsc41rVu3jsMPPzySJIlMJhNJksSPfvSjeOSRR9Zb8+abb45///d/z9kVpEOHDjk7jAAAAAAAAAAANGTFaT340EMPjUcffTQiIioqKuLFF1+Mww47bJ3rLrroonjiiSciIiKTycTixYvj+OOPj7322isOPPDAaN26dcydOzeeeeaZmDRpUk5wJJPJxAUXXFCr7wUAAAAAAAAAkKbUwiDHH398XHTRRdn1vffeu94wyKGHHhonnnhiPPDAA5HJZLJBj/feey/ef//97HVJkkREZHcFyWQysfvuu8eFF15Y2BcBAAAAAAAAAKhDUhsTs8MOO8SAAQOyo2Luv//+WLx48XqvvfXWW6Nv3745gY/qUEj1p/pYxJfBkPbt28eIESOiWbNmtfZOAAAAAAAAAABpSy0MEhHx0ksvRVVVVVRVVcXixYujRYsW672uRYsW8fTTT8eZZ54ZEbFOAGTNEEiSJHHQQQfF2LFjY4899qi1dwEAAAAAAAAAqAtSGxOzuVq0aBG33nprXHTRRXHffffFyJEjY9q0aTF37txo3rx5dOzYMQ488MAYMmRIDBw4MO12AQAAWMOwie/EsInvbPB81f/tBLmmrz3/YBT9X/h/Qy7u1jMu7tazxv0BAAAAQENSb8Ig1fbee+/Ye++949e//nXarQAAALCJFlWujM9XLN2se2ZULNukugAAAABArnoXBgEAAKD+aVnSOHZo0rwgdQEAAACAXMIgAAAAFJxxLgAAAABQe4RBAAAAALYSN/3pqbjplqfyXvfcs4+Mc390ZN7rAgAAAFtGGAQAAABgK7F4yfKYMbO8IHUBAACAukMYBAAAAGAr0WKbptGxQ9kGz1dVJTFr9oKcY9u13zaKijIbrQsAAADUHcIgAAAAAFuJc3/01eNc5s5bFHv2vCDn2PPP/DratmlZ6NYAAACAPCpKuwEAAAAAAAAAAPJHGAQAAAAAAAAAoAERBgEAAAAAAAAAaECEQQAAAAAAAAAAGhBhEAAAAAAAAACABkQYBAAAAAAAAACgAREGAQAAAAAAAABoQIRBAAAAAAAAAAAaEGEQAAAAAAAAAIAGRBgEAAAAAAAAAKABEQYBAAAAAAAAAGhAitNuYGtRVVUVb7zxRrz77rsxe/bsSJIk2rRpE927d4++fftGSUlJ2i0CAAAAAAAAAA2AMEiBLVmyJK655pq4+eabY/bs2eu9plWrVnH66afHZZddFu3atauVvrp06RKfffZZjWrcfvvtcfrpp+enIQAAAAAAAAAgL1IbE/Pf//3fsWjRorQeXytef/312GuvveJXv/rVBoMgERELFy6M66+/PvbYY4946qmnarFDAAAAAAAAAKChSS0M8u///u+xww47xNlnnx3jx49Pq42Cee211+KQQw6JqVOnrnOutLQ0mjZtus7x+fPnx9FHHx2PPvpobbQIAAAAAAAAADRAqY6JWbZsWfzlL3+Jv/zlL7HvvvvGj3/84zjppJOiSZMmabZVY3PmzInjjjsulixZkj1WXFwc559/fpx77rmxyy67RCaTialTp8Zf/vKXGDZsWCxdujQiIlatWhUnn3xyvPHGG7HbbrvVWs//9V//FW3atNmse/r371+gbgAAAAAAAACALZVqGCQiIkmSiIgYN25cnHnmmXHxxRfHaaedFj/60Y9i9913T7m7LXPFFVfEjBkzsuvS0tJ48MEH49vf/nbOdTvttFP86le/im9961sxaNCgKC8vj4iIJUuWxMUXXxyPP/54rfV88sknR5cuXWrteQAAAAAAAABAYaQ2JqZaJpOJTCYTEV8GQ8rLy+P666+P7t27x6GHHhp///vfY/Xq1Sl3uemmTJkSt956a86xK6+8cp0gyJr69u0b//M//5Nz7IknnohXX321ID0CAAAAAAAAAA1XamGQESNGxGGHHRYRX4ZAqkMhmUwmkiSJJEni+eefjyFDhkTnzp3j8ssvj+nTp6fV7iYbPnx4rFy5Mrveeeed4z/+4z82et/3vve9OOCAA3KOXXXVVXnvDwAAAAAAAABo2FILgwwePDieeuqp+Pjjj+M//uM/ok2bNtkQyNqhkJkzZ8Z//dd/xc477xyDBw+Of/7zn2m1vVEPP/xwzvqss86K4uJNm8Zz9tln56yffvrpWLZsWb5aAwAAAAAAAAC2AqmPienWrVtcc801MX369LjzzjtjwIAB64RCqoMhq1evjsceeyyOOuqo7H1z585N+xWy3nzzzZg6dWrOsZNOOmmT7//Od76TExxZvnx5PP3003nrDwAAAAAAAABo+FIPg1Rr3LhxnHLKKfHyyy/H22+/Heecc05ss802G9wtZPLkyfGzn/0sOnfuHD/4wQ/ilVdeSfsVYtSoUTnr7bbbLnbZZZdNvr9Zs2bRq1evnGPPPvtsPloDAAAAAAAAALYSdSYMsqYePXrEjTfeGF988UXceOON8bWvfW2Du4VUVFTEPffcEwcddFD07NkzbrrppliyZEkqfX/wwQc56/3333+za/Tr1y9nPWHChBr1BAAAAAAAAABsXepkGKRa8+bN45xzzok333wzRo8eHaecckqUlpZGkiQREevsFvLee+/F+eefH9tvv32ce+658fbbb9dqvx9++GHOumvXrptdY+171q5ZSFOmTIknn3wy7rzzzrjrrrviH//4R7zxxhtRWVlZaz0AAAAAAAAAADVTnHYDm6pfv37Rr1+/uO666+K2226LW265JT799NOI+DIUEhHZUMiSJUvilltuiVtuuSX69u0bP/7xj2PIkCHRuHHjgvb48ccf56x33HHHza7RuXPnnPXnn38eS5cujebNm9eot43Zd999Y968ees917Rp0+jfv3+cddZZMWTIkCgurjf/swEAAAAAAACArU6d3hlkfVq3bh0/+clP4uOPP45//vOfMXjw4GjUqNF6R8gkSRKvvfZanHbaabH99tvHpZdeGlOnTi1Yb+Xl5TnrDh06bHaNjh07brRuIWwoCBIRsXz58hg1alScfPLJseuuu8Zzzz1X8H4AAAAAAAAAgC1T78IgazrssMNixIgR8dlnn8V3vvOd7PiYiHVHyMyfPz/+8Ic/RLdu3eK73/1ufPTRR3ntZfny5bF69eqcY82aNdvsOk2bNl3n2JIlS7a4r3ybMmVKfPOb34yrr7467VYAAAAAAAAAgPWo1/M+Kisr4/7774+bb745Ro8enQ1/VI+NiYicr5MkidWrV8cDDzwQI0aMiHPPPTd+//vfrzeAsbmWLl26zrEmTZpsdp319bK+2vnQqFGj+PrXvx6DBg2KPn36xJ577hllZWVRUlIS8+fPjw8//DCee+65+POf/xwzZszI3ldVVRWXXnpptGnTJs4666wtfv706dO/8vyazwQAAAAAAAAANk29DINMmjQp/vSnP8Xtt9+eHW+y5piY6nVERElJSVRWVkZE5JxbtWpV/PGPf4xRo0bFyJEjt2iky5qWL1++zrHGjRtvdp3S0tJNql1Tl1xySRx77LGxww47rPd8hw4dokOHDnHwwQfHZZddFr/85S/jmmuuydl95ZxzzokDDjggdt999y3qoXPnzlt0HwAAAAAAAACwYfVmTEySJPHII4/EkUceGbvttlv84Q9/iLlz52bDCWsGPYqLi+O73/1uvPzyyzF//vy4+eabo3fv3tmRMWuOkHn//ffjmGOOiaqqqhr1t75dQFauXLnZdSoqKjapdk39+Mc/3mAQZG2NGzeOq666Km644Yac46tWrYrLLrss770BAAAAAAAAAFuuzodBZsyYEb/61a9ip512iuOPPz5GjhwZVVVV64Q6kiSJjh07xpVXXhlTp06Ne+65JwYMGBDNmzePs88+O15//fV4+eWXY9CgQesESN5444249957a9TnNttss86xFStWbHad9e0Csr7aaTj//PPj+OOPzzk2YsSImDVr1hbVmzZt2ld+xo4dm4+2AQAAAAAAAGCrUmfHxDz77LNx0003xWOPPRarVq3KGU+y9iiYAw88MBtUaNSo0QZrDhgwIJ544ol47LHH4pRTToklS5Zkz913333x/e9/f4v7bdq0aTRq1ChWr16dPbZs2bLNrlOXwyAREZdffnmMGDEiu06SJJ5++un4wQ9+sNm1OnXqlM/WAAAAAAAAAICoYzuDlJeXx7Bhw2L33XePww8/PB566KGorKzM2QWkeieQpk2bxg9/+MN4++2344UXXogTTzzxK4Mgazr66KPjmmuuydZNkiTGjx9f4/633XbbnPXMmTM3u8aMGTM2WjdNPXv2jB133DHnmB08AAAAAAAAAKDuqBNhkDFjxsTpp58enTp1ip/+9KfxySefZEe/rD0Kplu3bjFs2LD4/PPP409/+lP06NFji5555plnRklJSXY9d+7cGr/HbrvtlrOeOnXqZteYNm1aznr77bevUzuDRER07949Zz179uyUOgEAAAAAAAAA1pbamJilS5fG3XffHTfddFO88847EfGvsS/VY2CqjxUVFcWgQYPi/PPPjyOPPDIvzy8uLo4dd9wxJk2aFBERK1eurHHNPfbYI1599dXsurr25pg8efI6Neua1q1b56zLy8tT6gQAAAAAAAAAWFtqYZCOHTvG0qVLswGQiH+FQKqPlZWVxZlnnhk//vGPY+edd857D/necWPtHTO2ZHzKmDFjctZ77rlnjXoqhAULFuSsW7VqlU4jAAAAAAAAAMA6UguDLFmyJDsCplp1CKRXr15x3nnnxcknnxxNmjQpaB9rhlFqauDAgTnrWbNmxaeffhq77LLLJt2/bNmyeOutt3KOHXrooflqL28++eSTnHX79u1T6gQAAAAAAAAAWFtqYZA1JUkSJSUl8Z3vfCfOO++8+PrXv14rzz3nnHNi5syZeavXu3fv6Ny5c0ybNi177L777ovLLrtsk+4fMWJEVFZWZtdNmjSJww8/PG/95cOnn366ThikZ8+eKXUDAAAAAAAAAKwt1TBIkiTRsWPH+NGPfhQ/+tGPYrvttqvV5//oRz/Ke83BgwfHf//3f2fXf/nLX+LSSy+N4uKN/1HfcsstOevDDjssmjdvnvcea+I3v/nNOseOPPLIFDoBAAAAAAAAANanKK0HH3jggXHvvffGZ599Fv/5n/9Z60GQQhk6dGiUlJRk15MnT45rr712o/fde++98dJLL+Ucu/TSSzd6X/WonerP6aef/pXX12Qszr333ht//etfc44dfPDBsdNOO21xTQAAAAAAAAAgv1ILg7zwwgsxZMiQTdoxoz7Zeeed46yzzso5dsUVV8QTTzyxwXvGjh0b5513Xs6xQYMGFWRczosvvhhHHXXUOsGTjbn++uvj1FNPzQmTZDKZuPrqq/PdIgAAAAAAAABQA6mFQRqyK6+8Mjp06JBdr1ixIgYPHhxD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/1nkvBtuuEGdO3c2jb388suW5ydJ69ev108//WQae/PNNxUZGVnovPLly2v8+PGmsY8//lgnTpywPEcAAAAAAAAAAAAAAOAZmkEs9t1335m2R48erYiICJfm3n777abtH3/8Uenp6ValZvftt9+aths2bKiePXu6NPf6669XbGysfTsnJ0dz5syxND8AAAAAAAAAAAAAAOA5mkEstH79eu3fv980dt1117k8/5prrjE1jpw7d04//vijZfmdN2vWLNP2sGHDXJ5bpkwZDRw4sNB4AAAAAAAAAAAAAADAf2gGsdDChQtN21WqVFGDBg1cnl+6dGm1atXKNPbLL79YkZrdyZMntXHjRtPYZZdd5laMTp06mbbzP28AAAAAAAAAAAAAAOA/NINYaMuWLabt9u3bux2jY8eOpu2tW7d6lVN+zuJ16NDBrRj5c0xJSdHBgwe9ygsAAAAAAAAAAAAAAFiDZhALbdu2zbRdr149t2Pkn5M/prfyx4uPj1eFChXciuHseVmdJwAAAAAAAAAAAAAA8AzNIBbasWOHabtWrVpux6hZs6Zp+9ChQ0pLS/MqrwtZkWP58uVVpkwZ09j27du9ygsAAAAAAAAAAAAAAFiDZhALnTlzxrSdmJjodoyqVasWGdcbp0+fNm17kqPkmKeVOQIAAAAAAAAAAAAAAM9F+DuBUHHu3Dnl5uaaxkqXLu12nFKlSjmMpaamepxXUbE8yVFyzNPKHJ256qqrFB0dbUms66+/Xg888ECh+7z11lv68ssvLTneeb///nuhjx8/flxXX321pce8//77dcMNNxS6z5NPPqmFCxdadszKlStr9uzZhe6zadMm3X777ZYdU5LGjx+vXr16FbrPbbfdpj///NOyYzZr1kwfffRRofv88ssveuqppyw7piR9+OGHat68eaH7XHXVVTpx4oRlx+zZs6deeOGFQvf54osv9Pbbb1t2TEmaNWuWEhISCt3n0ksvtfSYnCPMOEd4jnOEGecI73CO+B/OEd7hHGHGOcJznCPMQukckdioQaH7cI7wHOcIM84RnmMdYcY5wjucI/6Hc4R3OEeYcY7wHOcIM84RnuMcYcY5wnPFdY7IzMz0ar4zNINYxNmtXGJiYtyO46wZxMrbxOSP5UmOkmOenuR48ODBQh8/cuSI/d/r1693O35BXDnB7tu3TytWrLDsmK7I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ZIi++eYb+1ipUqX0/vvvu33cYMG6FEWhFksGajG4UaeeY23qG6F5vRPAC8OGDdPkyZPt23PnztXo0aPdipGSkqLPPvvM5f0XLVqkjIwMp4+1bdvW4R5jwe7o0aPq1auXGjZsqEGDBunyyy9Xq1atlJCQIOnvv8o5ceKEfvnlF33xxRf6/vvvTfPr16/v1vf3QseOHdP69evt2w0aNNAll1zi+ZOBT1CHxWPNmjVas2aN08d+//13h7HCFo833XSTYmNjXToudRgaqFPPTJkyxbQdHR2tG264wfLjUGehw5taMwxD8+bN07x581SvXj1de+21uuyyy9SqVSvVqFFDYWFh9v127typhQsX6t1339Wff/7pEGvcuHFq166dNU8qwLA2RVGow+LB2hTeoE49w9oU7rDi/wHHjh2rPXv2qH///urfv7/atWunhg0b2ussPT1d69at06xZs/Thhx8qOTnZPjcsLExTp05VgwYNrHlCAYh1KVxBLRYP1qbwBnXqGdamPmIAMMnJyTESExMNSYYko3Tp0kZ6erpbMf766y/7fG+/xo0b59Hxnn32WQ+/A763fv16p881KirKqFixohEREVHg9+Piiy829u/f7/Gx33vvvaD5PpVk1GHxGDdunGXfo7/++svl41KHoYE6dV9WVpZRqVIl0/Gvu+46nxyLOgsd3tTaokWLCqwZm81mxMbGGhUqVDDCwsIKra8HH3zQrZz9XWvuYm2KolCHxYO1KbxBnbqPtSncZcX/A7Zs2dLhfR8WFmaUK1fOKFOmTIH1FRkZaXz++edu5+zvOnMX61K4glosHqxN4Q3q1H2sTX2H28QA+YSHh5supZeenq4ffvjBjxkVbcuWLaZtm82mIUOG+Ckbz2VlZenUqVPKyclxeMxms+nWW2/VqlWrVLNmTY+PMWPGDPu/w8LCNHLkSI9jwXeow9BGHYYG6tR9c+bM0cmTJ01jo0aN8smxqLPQ4ataMwxDKSkpOn36tPLy8pzuU7lyZc2cOVNvvPGGW7H9XWtWYW2K86jD0EYdhgbq1H2sTeEuX9VZXl6ezp49q7S0NKePN23aVL///rtHfxns7zqzCutSXIhaDG3UYmigTt3H2tR3aAYBnLj33nsVHh5u3540aZIfsyla/vuNXXvttWrWrJl/knFB3bp1NXbsWLVr104REYXfraps2bIaPny41q5dq0mTJqls2bIeH3fPnj1atGiRffvqq69WnTp1PI4H36IOQxN1GFqoU/d88sknpu1q1aqpd+/elh+HOgs9ntZaq1at9N///lfDhg1z+RfDkZGRuvTSSzVx4kTt27dPgwcPdjtff9eau1ibwhXUYWiiDkMLdeoe1qbwhLf/D/jEE09o0KBBKleuXKH72Ww2dezYUVOmTNGGDRvUpk0bT9L1e525i3UpXEUthiZqMbRQp+5hbeo7NsMwDH8nAQSi66+/XtOnT5f0d2fYnj17VLt2bT9n5Vz79u21evVqSX+f+Ddt2qSmTZv6OSvXpKena+PGjdq1a5eOHz+utLQ0RUVFKSEhQRdffLHatGmjyMhIS4715JNP6sUXX7RvL126VF26dLEkNnyDOgw91GHooU4DD3UWmqyotdOnT2vbtm06cOCAjh07prS0NOXl5SkuLk7ly5dX3bp11aZNG8XExHiVazDXGmtTFIY6DD3UYeihTgMPdRZ6rKgzwzC0Y8cOe60lJydLkuLi4lS/fn21bdtWlStX9jrXYK4z1qUoCrUYeqjF0EOdBp4SWWf+u0MNENg2bNhg2Gw2+z2jHn74YX+n5FRycrIRHh5uz3PYsGH+TikgpaenG5UrV7Z/n7p27ervlOAC6jC0UIehiToNLNRZ6KLWQgu1Gpyow9BCHYYm6jSwUGehiToLLdRp8KIWQwu1GJqo08BSUuuM28QABWjRooWGDh1q3/7ggw909uxZ/yVUgGXLlik3N1fS352FY8eO9XNGgWnSpEk6ceKEffuFF17wYzZwFXUYWqjD0ESdBhbqLHRRa6GFWg1O1GFooQ5DE3UaWKiz0ESdhRbqNHhRi6GFWgxN1GlgKal1RjMIUIjnn3/efrm9lJQUvfPOO37OyNGF9/EaOnRoSF62yVtZWVl67bXX7NtXXnmlOnfu7MeM4A7qMDRQh6GNOg0M1Fnoo9ZCA7Ua3KjD0EAdhjbqNDBQZ6GNOgsN1GnwoxZDA7UY2qjTwFCi68zflyYBAt0///lP+yWD4uPjjZMnT/o7JZMOHToYkoywsDBj8+bN/k4nIL311lv21zAqKsrYsWOHv1OCm6jD4Ecdhj7q1P+os5KBWgt+1Grwow6DH3UY+qhT/6POQh91Fvyo09BALQY/ajH0Uaf+V5LrzGYYhuGTLhMgRKSkpKhx48Y6cuSIJGnMmDF6/fXX/ZwVXJWSkqL69evbL/302GOP6aWXXvJzVnAXdRjcqMOSgTr1L+qs5KDWghu1Ghqow+BGHZYM1Kl/UWclA3UW3KjT0EEtBjdqsWSgTv2rpNcZzSAAAAAAAAAAAAAAAAAhJMzfCQAAAAAAAAAAAAAAAMA6NIMAAAAAAAAAAAAAAACEEJpBAAAAAAAAAAAAAAAAQgjNIAAAAAAAAAAAAAAAACGEZhAAAAAAAAAAAAAAAIAQQjMIAAAAAAAAAAAAAABACKEZBAAAAAAAAAAAAAAAIITQDAIAAAAAAAAAAAAAABBCaAYBAAAAAAAAAAAAAAAIITSDAAAAAAAAAAAAAAAAhBCaQQAAAAAAAAAAAAAAAEIIzSAAAAAAAAAAAAAAAAAhhGYQAAAAAAAAAAAAAACAEEIzCAAAAABAkjRlyhTZbDbT1969e302D9bg+w8A8NRHH31k+vnx6KOP+jsleOiHH34wvZbDhw/3d0oAAADwM5pBAAAAAAAAAKCEOX36tB5//HH7dsWKFfXEE0/4MSN4o3///uratat9+7PPPtOyZcv8mBEAAAD8jWYQAAAAAB7Zu3evw9UIunfvbknsxYsXO8QeNWqUJbEBwBvOzn2FfZUqVUqJiYlq3LixBg4cqGeeeUa//PKL8vLy/P1UAJRwTzzxhE6dOmXffuqppxQfH1/kvDp16vjsilTOzqOBZu7cuQ45NmzY0GfHe++99xyOd8UVVzjd95VXXjFt33vvvcrNzfVZbgAAAAhsNIMAAAAAAPzimWeeCfgPfABvZWRk6NixY9qxY4fmzJmjZ599Vpdffrnq16+v1157TTk5Of5OESiUswaoKVOm+DsteGnr1q2aOHGifbtKlSq68847/ZhR8OjTp4+qV69uGtu1a5eWLl3qk+N9/PHHDmOjR492um+HDh3Up08f+/aGDRv06aef+iQvAAAABD6aQQAAAAAAAIrZ3r179fDDD6tjx47auXOnv9MBUMI8/fTTpitGjBkzRjExMX7MKHiEh4c7vWLd5MmTLT/Wn3/+qTVr1pjGKlSooEGDBhU458Jb/0jSs88+q6ysLMtzAwAAQOCjGQQAAAAAAMALZcqUUcuWLZ1+NWzYUOXLly9w7tq1a3X55Zfr4MGDxZgxgJJs3bp1mjlzpn07Li5Od999tx8zCj633nqrwxXNZsyYodTUVEuP4+yqIMOHD1d0dHSBc7p166YOHTrYt/fu3Wu6CgwAAABKDppBAAAAAACSpFGjRskwDNNXnTp1/J0WisDr5n9t27bVH3/84fRrx44dOn36tHbt2qXx48erUqVKDvP379+voUOH+iFzACXRyy+/LMMw7NsjRoxQbGysHzMKPvXq1VP37t1NY2lpafrqq68sO0Z2dramTZvmMH7rrbcWOfeuu+4ybb/22mvKy8uzLDcAAAAEB5pBAAAAAAAAfKx+/fp68skntWnTJrVv397h8RUrVmjGjBl+yAxASbJv3z598803prE77rjDT9kEt9GjRzuMObuSh6fmzJmjEydOmMbatGmjli1bFjl32LBhio+Pt2/v2bNH3377rWW5AQAAIDjQDAIAAAAAAFBMEhMTNWfOHCUmJjo89sEHH/ghIwAlyTvvvKPc3Fz7drt27dS8eXM/ZhS8rrnmGpUrV8409ttvv2nnzp2WxHfWWOKsAcWZUqVK6YYbbjCNvfXWW5bkBQAAgOBBMwgAAAAAAEAxqly5sh555BGH8WXLlik9Pd0PGQEoCXJycvTpp5+axrhFlediYmJ04403OoxbcXWQo0ePav78+aaxUqVKOT1eQfK/tr/++qt2797tdW4AAAAIHhH+TgAAAAAAfC01NVXbtm3Tjh07dOrUKaWkpCg6Olrly5dXQkKC2rZt6/Sv9H0hPT1dK1eu1Pbt23XmzBlFREQoMTFR7du3V+PGjV2Oc+rUKa1atUq7du1SSkqK4uLiVLVqVXXr1k2VKlXy4TMITsePH9eaNWt0/PhxHT9+XOHh4UpISFCVKlXUsWNHxcXF+TyHvLw8rVu3Tps2bdLx48dls9lUqVIl1atXT506dVJUVJTPcyhKbm6u9uzZo23btunQoUNKTk5Wbm6uypcvr/Lly+uiiy5S8+bNFRZWPH9bsnPnTq1du1aHDh1SZmamKlasqGrVqqlz584qX758seTgK0OGDNFDDz1kGsvMzNTmzZvVrl27QucG4uu0YcMGHTx4UKmpqYqKilJiYqJGjhzp0vxDhw5p27Zt2rt3r5KSknTu3DnFxcWpQoUKqlWrltq1a6eYmBgfP4u/7d+/X2vWrNG+ffuUlpam2NhYNWjQQJ06dXLrPbd161atX79eR44cUVZWlhISElS/fn117txZERHW/zrOMAxt2rRJu3fv1okTJ3Tq1CmVKVNGlStXVp06ddSuXTufHNcXzp49q9WrV+vYsWM6ceKEMjMzValSJSUkJKhdu3aqWrWqz3M4/zPjr7/+UlJSkv18PXjw4CJ/xp47d06bN2/W1q1bdebMGaWkpCg8PFylS5dW+fLlVbt2bdWvX1/Vq1f3+fPIb8GCBTp27Jhp7Nprry32PELJ6NGj9d///tc0NnXqVI0fP17h4eEex506dapycnJMY0OGDDHd+qUo3bp1U+XKlU23mpk6daqeffZZj/MCAABAkDEAAAAAwAN//fWXIcn01a1bN0tiL1q0yCH2zTff7PL87OxsY8GCBcb9999vtGjRwrDZbA7x8n/Vr1/fePrpp40TJ054lPPkyZMdYv7111/2x7dt22YMHz7ciImJKTCH1q1bGz/88EOhx1m6dKnRt29fIzw83GmM8PBwo0+fPsaff/5p+XOwYl63bt2KfC2K+po8ebJLzyc9Pd145ZVXjDZt2hT6HoiIiDC6dOliTJo0ycjJyXH9G/b/nL1fFy1aZH88KSnJGDt2rFGlSpUCcyhTpowxatQoY//+/W4f39PX7bzt27cbL730knHFFVcYZcqUKfL7Hx8fb1x77bXGihUr3M71vPwxx40bZ38sNzfX+Pjjj41mzZoVmEN4eLjRq1cv4/fff/c4B09Zee5z9v0u6BwQaK9Tamqq8dJLLxn16tUrMIeCnDhxwvjwww+NYcOGFVoX57+ioqKMrl27Gl999ZWRm5vr0XPJf+7J/5pNnz7daNu2bYE5REdHGyNGjDAOHDhQ4DEyMjKMt956y2jQoEGBccqVK2c8/vjjRlpamkfPI7/Vq1cbI0aMKPL7GBsbawwZMsRYuXKlS3GdnVfc/XKnLtLT043XXnvNuPTSSwv8+Xb+q2nTpsaECROM1NRUt79fhb0P8vLyjM8++8zo2LFjgT8zLjy35zdz5kxjwIABRmRkpEvfn2rVqhlDhw41pk2bZiQlJbn9XDwxfPhwUw5NmjTxKE7t2rW9+rlTGHfOJYGiVatWLp/LXXXRRRc5xFy4cKHbcUaOHGmK0aBBA6/yAgAAQHAJ/NU0AAAAgIAUqM0g06dPNypVquTxh1elS5c23nnnHbdzLuwD+XfffdeIjo52OYcHHnjAyMvLM8XPzMw07rrrLpdjREREGFOnTrXsOVg1r7iaQb788kujevXqbsdu2rSpsWTJEre+b4U1gyxdutStPEqVKmXMmjXLreN7+rqdPHnSuOSSS7x6La6++mrjzJkzbuVrGAU3GRw8eNC49NJL3crhiSeecPv43rDy3FetWjWHWJ999plpn0B8nVasWGHUqlWryOM6c8MNNxgREREeP5eLL77Yo2a3gpoAkpKSjP79+7t8/Pj4eOOXX35xiL9ly5ZCG5jyfzVo0MCj5q/z9u7dawwZMsSj7+GQIUOKfD8UZzPIRx99ZFStWtXt+FWqVDFmzJjh1vetoPfB0aNHja5duxZ5TGfNIPv27XNpbmFfjz76qFvPwxO5ubkO66O7777bo1g0g5j95z//ccj52muv9Tjeb7/95hCvXr16DmtDVzir5e3bt3ucGwAAAIJL8VwvFAAAAACKyZYtW3Ty5EmP56enp+vee+/VXXfdZUk+L774ou655x5lZma6POett97Sk08+ad/OysrSoEGD9N5777kcIycnR6NGjdKsWbPcyjcUPP/887r++ut16NAht+du3rxZvXv31hdffOF1HnPmzNHll1/uVh7nzp3TNddco/nz53t9/KKkpKRo/fr1XsWYNWuW2rdvr4MHD3qdz549e9ShQwf9/vvvbs178cUX9dRTT3l9fH9ISkpyGCtXrpxpO9Bep6VLl6p79+7av3+/R/OXL1/ucOsDd2zdulUdO3bUzz//7HGM81JSUtSjRw/98MMPLs9JSkrSwIED9ccff9jH/vjjD3Xp0kV//vmny3F27dql7t27O30PFGXFihVq3769Zs6c6fZcSZo5c6Y6duyoXbt2eTTfKtnZ2frHP/6h2267TUeOHHF7/rFjxzRs2DA9//zzXuVx9OhRderUSUuXLnV77t69e9W5c2eP5ha31atXO6yPunfv7p9kQsxNN93kcCur2bNn69SpUx7Fmzx5ssPYrbfeKpvN5nasHj16OIzNmzfPo7wAAAAQfILjZqEAAAAA4KHatWvrkksuUZMmTVSjRg3FxsaqVKlSSk1N1eHDh/XHH39owYIFDh/Ivf/++2revLnuvvtuj4/93XffmZo6qlSpogEDBqh169aqVKmSUlJStGHDBn311Vc6duyYae6ECRM0aNAgtW/fXvfcc4/pF/cXXXSRBgwYoIYNG6pcuXI6ffq0li1bpq+//trUdJKXl6e77rpL3bt3d+se877UoEEDnT17VtLfH8Dlf94tW7YsMkaFChUKfOz555/X2LFjHcYjIiLUo0cPXX755apevbpycnJ04MABzZ07VytWrJBhGPZ9s7KydNNNNyk8PFzDhg1z8ZmZ/fHHH3r88ceVlZUlSSpVqpR69eqlrl27KjExURERETpw4IB+/PFH/fLLL6a5OTk5+sc//qHNmzcX6+tWtmxZtWvXThdffLEaNmyo+Ph4xcbGKisrS2fOnNGWLVu0aNEibd261TRv586duu6667RkyRJFRHj2a4aUlBT169fP3jhjs9nUqVMnXX755apVq5bKli2rEydO6LffftO3336rjIwM0/wJEyZo4MCB6tChg2dP3g/27duntLQ0h/HKlSsXOs+fr9PRo0c1ZMgQ0/e/ffv2uuKKK1S7dm3FxsbqyJEj2rJli2bMmFFkvPDwcLVu3VpNmzbVRRddpIoVKyouLk6GYSg5OVk7d+7UihUr9NtvvykvL88+LzU1Vddff73Wr1+vmjVrevRcJGnkyJFat26dfbtNmzbq16+f6tatq7Jly+ro0aNauHChvv/+e9Px09PTdfPNN2vdunU6efKkBgwYYP/QNzIyUj169FDPnj1VrVo1RUREaO/evZo1a5ZWrlxpOv6ePXv0+OOP67///a/LOS9evFj9+vVzqIGwsDB16dJFnTp1Ut26dVWuXDmdO3dOBw8e1JIlS/TLL78oNzfXvv/27dt15ZVXas2aNYqLi3M4ToUKFezn46ysLIf3U82aNQs9F0t/n+8LkpeXp0GDBmnu3LkOj1WrVk29evXSJZdcokqVKikmJkanT5/W+vXrNW/ePFMjkmEYGjt2rCpVquRRE2deXp6GDRumPXv22Mfq1aun/v3766KLLlKlSpV06tQp/fXXX/rmm28c5t966606cOCAw3irVq3UvXt3NWrUSOXKlVNkZKRSUlJ05swZbdu2TRs3btSaNWtMr4mvLVmyxGGsbdu2xXb8UFa+fHkNHjzY1EialZWlzz77TPfff79bsdLT0zV9+nTTWHh4uEaNGuVRbrVr11blypV14sQJ+9jixYv1wAMPeBQPAAAAQcbPVyYBAAAAEKQC9TYx48aNM5o3b268+eabxo4dO1yak5GRYbz99ttGXFyc6ZjR0dHGwYMHXYrh7DLc528NEx4ebjz//PPGuXPnnM5NSkpyern/K664wvjmm2/s25UrVza++uqrAnPYuXOn0ahRI4c4L774osfPwerbxFxo3Lhxll4KftmyZUZ4eLhDzM6dOxd6SfTly5cbF110kcO8cuXKGfv27SvyuM7erzExMfZ/jxgxwjh8+HCh8ytUqOAQ46WXXnLpeXv6/f/rr7+McuXKGffee6+xePFiIysry6Xj/fbbb0bbtm0djvnqq6+6NN8wHG8DcOH3q0OHDsbatWsLzbt169YOMfr06ePy8b1h1bnv9ddfd4gTFRVlpKamOhwvUF6nC+urRYsWxvLlywucW9D5rmHDhsaQIUOMmTNnGmfPnnUpj7179xo33HCDQz79+/d3+bnkvz3Ihbfuqlu3rvHTTz8VOHfNmjVGlSpVHI7/+eefGwMHDrRvX3755YX+3Pn4448dzlFhYWHGgQMHXHoOR44ccZrHLbfcUuS5ateuXUafPn0c5rpyKwtn73lXbtdVmLFjxzrErFGjhvHVV18ZOTk5Bc7Lzs42PvroI6Ns2bIOtVPYeeO8/O+DC1+PihUrGlOnTi3wVhx5eXlGRkaGffvXX391eA716tUzli1b5tL34PTp08Znn31mdO3a1XjsscdcmuONa6+91pRrbGysR7cdMQxuE+PMzz//7JB3q1at3I4zZcoUhzj9+vXzKrfLL7/cFK969epexQMAAEDwCI7VNAAAAICAE6jNIK5+uOjMhg0bHBpCHn/8cZfmOvtA/vwHfTNnzixyflZWltGsWTPTXJvNZlSqVMmQZFStWtWl5pZdu3aZPuSUZDRq1Mjj5xAszSB5eXlG48aNnX5YnJmZWeT8U6dOOXz/JRkDBgwocq6z9+v5r+eff96l/H/99VfDZrOZ5jZo0MCluZ5+/zMzM4309HSXjpHfuXPnjL59+5qOWbNmTSM7O9ul+QV9vwYMGFBgE8GFTp065fCheFhYmEvNO96y4tx34sQJIzEx0SFOz549HfYNxNfpsssuM5KSkjzKyZtz9DPPPONwjty2bZtLc/M3AZz/uvjii40jR44UOf+3335zqNGEhAT7v2+44QaXvq/jx493yOGFF15w6Tn069fPNC88PNz47LPPXJprGH+fJ2+55RaH469cubLQeVY3gyxfvtwICwszxbv00kvdem/88ccfDj+vXfnAvKD3QZUqVYzNmze79TwefvhhU4zIyEhj586dbsU4Ly0tzaN57qhTp44p344dO3oci2YQR3l5eUbdunUdcl+3bp1bcZy9R7/++muvchszZoxDzMKaVAEAABA6wgQAAAAAFlmzZo1atWrl9dc//vEPj3Pw5rYaLVq00IsvvmgamzRpksfxJOmxxx7T4MGDi9wvMjLS4fYmhmHo5MmTkqRPP/1UDRs2LDJO/fr1dcstt5jGduzYod27d7uRdfD54YcftH37dtNYrVq1NH36dEVFRRU5v0KFCpo9e7ZKlSpVZFxXDRkyRE899ZRL+3bu3FlDhw41je3atcunr1tUVJTD83VVTEyMPvnkE5UuXdo+dv62N56qU6eOpk2bppiYmCL3rVChgsaNG2cay8vL008//eTx8YvLsWPHdNVVV+no0aMOj912220OY4H2OsXHx2v69OlOby3i6nxPjR07Vu3atbNvG4bh1Tk6Ojpa06dPV2JiYpH7durUSf369TONHT9+XJLUuHFjTZw40aXb7/zzn/9UuXLlTGMX3gasIKtXr3bY76WXXtKNN95Y5NzzbDabPvjgA1188cWm8QkTJrgcwwrjx4833XanWrVqmjt3rlvvjZYtWzrcXmfevHnasGGDRzlNnDhRTZo0cWvOhbeWkaTu3bsXemucwlxYo76QlZWlffv2mcZq167t02OWNDabzWH9JUkff/yxyzF2796tpUuXmsYqV66sq666yqvcnL3WO3bs8ComAAAAggPNIAAAAAAsk5aWpg0bNnj95c/GheHDh8tms9m3jx8/7vEvzMuVK6cnnnjC5f0HDBig6Ohoh/HevXurV69eLse59tprHcbWrVvn8vxg9M477ziM/fvf/1aZMmVcjlG3bl09+uijpjHDMPTuu++6nU9YWJheeeUVt+YMHz7cYWzt2rVuH7u4JCQkqG/fvqaxZcuWeRxv3Lhxbn0YfP311ys8PNw0Fsjfrz179mjChAlq0aKFfv/9d4fH27Vrp+uuu87y41r9Oj300EOqXr26t2l5xGazacSIEaYxb57LiBEj1Lx5c5f3v+aaa5yOjx071uUP82NiYjRgwADT2IYNG2QYRqHzXn75ZdN2gwYN9NBDD7l0zAtFRkY6/FyaN2+eMjMz3Y7liT///FNz5841jb344osODTKuuPHGGx2aJL/77ju34/To0cPhNXFFSkqKabtixYpuxygu+/btc3iP+auOQ9moUaMUFmb+dfvnn3/ucn1NnjzZ4XUaMWKE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qJKTk5WVleVQK+PGjfND5iVLIL1O7t5WJb+XX37ZaSNI9erVdffdd2vatGn6/fffdeDAAZ09e1YZGRkOz2XRokVe5RCMrL5yhr8E4vPw9j0tSQ8//LD+/PNP3XTTTYqJiSl035ycHC1btkz33XefateurX/961/FcrsOZz/XvGkAcvZ9s6K5xFlOwXgFk6ZNm6pDhw6msZ07d+rXX391ur+zW8TceuutluXj7PvqzToJAAAAwYMrgwAAAAAIGY899pjDX1b27dtXH3/8sapWrepynOL4C2lYx9lfznrz4ZqzuVb9dW6g+OGHH/Tzzz+bxhISEvTpp5/qiiuucDkOteJbofQ6HT9+XC+99JJpLCIiQq+++qruvfdelz+UD4TnUtycXdVh69atuuiii/yQjeecPY/rrrtOX375pR+ysVbjxo01bdo0vfvuu/rhhx+0aNEiLVu2TNu3b5dhGE7npKen69///rdmz56tH3/80aeNqM5uh+PuFa8u5OzqW6mpqR7HKyyGp7fL87fRo0dr5cqVprGPP/5YXbp0MY1t3LhR69atM401atTIYT9vOHutrbjtFwAAAAIfVwYBAAAAEBLS0tL0/fffm8Zat26t2bNnu9UIIgXmXy+jYM4+KDp79qzH8ZzNrVChgsfxAtEXX3xh2g4PD9f333/vVoOB5N2HiShaKL1Os2fPVnp6umns5Zdf1oMPPujW1RkC4bkUN2e3EgnG70OoPI/CxMfH68Ybb9RHH32krVu36tSpU5ozZ44effRRNW/e3OmcHTt2qH///srKyvJZXs4aTQ4ePOhxPKt/7hYWI1ibQa6//nqHq2/MmDHDoeFl0qRJDnOtvCqI5Py15ip4AAAAJQPNIAAAAABCwtKlSx2uCvL4448rMjLSrTgHDhxQdna2lanBxypXruwwtnXrVo/jbdmyxWHM2YeYweynn34ybfft21ft27d3O86ePXusSglOhNLrlP+5lC9fXvfdd5/bcQLhuRS3KlWqOIzt27fPD5l4p3LlyrLZbKaxYHwe7ihfvrz69++vCRMmaOPGjdq+fbvuuusuh1ufbN682WlTgFUqVqyouLg405g3zSDOfiZu27bN43jnOfvZHaw/f2NjYzV06FDTWFpamr766iv7dlZWlj777DPTPhEREbr55pstzeXQoUMOY3Xr1rX0GAAAAAhMNIMAAAAACAkHDhxwGPPkEtu///67FemgGLVu3dphbM2aNR7HW716tWnbZrM5PUawyszM1PHjx01jntRKbm6uVq1aZVVayCfUXqf85+gOHTq43awnlcxzdIcOHRzGli5d6odMvBMTE6OWLVuaxnbs2KFjx475KaPi16hRI/33v//V1KlTHR775ptvfHrsFi1amLa3b9/ucSxnPxM3btzocbzz/vzzT4exNm3aeB3XX0aPHu0wNnnyZPu/Z8+erVOnTpke79evnxITEy3NI3+jTnR0dNDdZgoAAACeoRkEAAAAQEg4efKkw5gnt/aYPn26FenABc5uDZGbm+t2nNatWysmJsY09t1333kU69ixY/r1119NY40bNw6p28Tk/+BJ8qxW5s6d63C5e1gn1F6n/OdoT57LyZMntWjRIqtSCho9evRwOF/OmTOn2K5iZdW5WpJ69+7tMDZz5kyPYgWzG2+8Ua1atTKNWdFMUZh27dqZtvft26fk5GSPYl122WUOY/PmzZNhGB7FO2/OnDkuHStYdO7cWY0bNzaNLVu2TDt37pQkffzxxw5znDWQeGvDhg2m7ZYtW3rUjAcAAIDgQzMIAAAAgJCQ/77skvMGkcLs3r1bs2bNsiolFCE2NtZhzJMPrSMjI9WjRw/T2NGjR/Xdd9+5HevDDz9UTk6OaeyKK65wO04gs6JWJOn111+3Ih0UINRep/zPx5Pn8u677yojI8OqlIJGXFycunfvbho7ePCgPv3002I5vlXnakm6+uqrHcb+/e9/O5x3S4L8V2ZISkry6fE6duzoMOZpA0qbNm2c3nbGm2atXbt2OVz5Jzw8XF27dvU4ZiC49dZbHcY+/vhjHT58WD/++KNpvEqVKurfv7+lx8/IyNCOHTtMY86uNgQAAIDQRDMIAAAAgJBQtWpVh7H8v2QvTF5enm699VaP/9oZ7itfvrzD2J49ezyKdc899ziMPfzww0pPT3c5xr59+zRhwgTTmM1m07333utRToEqPj5epUuXNo25UyuSNHHiRC1evNjCrJBfqL1O+c/Ry5cvV1pamsvzN2/erJdeesnqtILGU0895TD28MMPe3zOdEdsbKzD1UE8Pe5ll13m0NiyZ88e/fOf//Q0vaB15MgR03blypV9erxevXopLMz8q+D8V8JyVXR0tG677TaH8X/9618er6Meeughh7FrrrlG1apV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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(11, 7), dpi=200)\n", + "\n", + "layer_labels = [(int(key.split(\":\")[0]), int(key.split(\":\")[1])) for key in bf_energies.keys()]\n", + "plot_labels = [str(item) for item in layer_labels]\n", + "\n", + "plt.errorbar(\n", + " plot_labels,\n", + " sim_physical_energy_diff,\n", + " yerr=sim_physical_uncertainties.values(),\n", + " ecolor=(20 / 255.0, 26 / 255.0, 94 / 255.0),\n", + " color=(20 / 255.0, 26 / 255.0, 94 / 255.0),\n", + " capsize=4,\n", + " elinewidth=1.5,\n", + " fmt=\"o\",\n", + " markersize=8,\n", + " markeredgewidth=1,\n", + " label=\"Physical\",\n", + ")\n", + "\n", + "plt.errorbar(\n", + " plot_labels,\n", + " sim_logical_energy_diff,\n", + " yerr=sim_logical_uncertainties.values(),\n", + " color=(0, 177 / 255.0, 152 / 255.0),\n", + " ecolor=(0, 177 / 255.0, 152 / 255.0),\n", + " capsize=4,\n", + " elinewidth=1.5,\n", + " fmt=\"o\",\n", + " markersize=8,\n", + " markeredgewidth=1,\n", + " label=\"Logical\",\n", + ")\n", + "\n", + "ax.set_xlabel(\"Hamiltonian Parameters (U, V)\", fontsize=18)\n", + "ax.set_ylabel(\"Energy above true ground state (in eV)\", fontsize=18)\n", + "ax.set_title(\"CUDA-Q AIM Circuits Simulation (lower is better)\", fontsize=20)\n", + "ax.legend(loc=\"upper right\", fontsize=18.5)\n", + "plt.xticks(fontsize=16)\n", + "plt.yticks(fontsize=16)\n", + "\n", + "ax.axhline(y=0, color=\"black\", linestyle=\"--\", linewidth=2)\n", + "plt.ylim(\n", + " top=max(sim_physical_energy_diff) + max(sim_physical_uncertainties.values()) + 0.2, bottom=-0.2\n", + ")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running logical AIM on Infleqtion's hardware " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The entire workflow we've seen thus far can be seamlessly executed on real quantum hardware as well. CUDA-Q has integration with Infleqtion's gate-based neutral atom quantum computer, [Sqale](https://arxiv.org/html/2408.08288v2), allowing execution of CUDA-Q kernels on neutral-atom hardware via Infleqtion’s cross-platform Superstaq compiler API that performs low-level compilation and optimization under the hood. Indeed, the AIM research results seen in [our paper](https://arxiv.org/abs/2412.07670) were obtained via this complete end-to-end workflow.\n", + "\n", + "To do so, users can obtain a Superstaq API key from [superstaq.infleqtion.com](https://superstaq.infleqtion.com/) to gain access to Infleqtion's neutral-atom simulator, with [pre-registration](https://www.infleqtion.com/sqale-preregistration) open for access to Infleqtion’s neutral atom QPU." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a tutorial, let us reproduce the workflow we've run so far but on Infleqtion's QPU. We begin with the same GPU-enhanced VQE to generate the AIM circuits:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "cudaq.reset_target()\n", + "\n", + "if cudaq.num_available_gpus() == 0:\n", + " cudaq.set_target(\"qpp-cpu\", option=\"fp64\")\n", + "else:\n", + " cudaq.set_target(\"nvidia\", option=\"fp64\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Computed optimal angles=[1.5846845738799267, 1.5707961678256028] for U=1, V=-9\n", + "Computed optimal angles=[4.588033710930825, 4.712388365176642] for U=1, V=-1\n", + "Computed optimal angles=[-1.588651490745171, 1.5707962742876598] for U=1, V=7\n", + "Computed optimal angles=[1.64012940802256, 1.5707963354922125] for U=5, V=-9\n", + "Computed optimal angles=[2.1293956916868737, 1.5707963294715355] for U=5, V=-1\n", + "Computed optimal angles=[-1.6598458659836037, 1.570796331040382] for U=5, V=7\n", + "Computed optimal angles=[1.695151467539617, 1.5707960973500679] for U=9, V=-9\n", + "Computed optimal angles=[2.4149519241823376, 1.5707928509325972] for U=9, V=-1\n", + "Computed optimal angles=[-1.7301462945564499, 1.570796044872433] for U=9, V=7\n", + "\n", + "Finished building optimized circuits!\n" + ] + } + ], + "source": [ + "device_circuit_dict = generate_circuit_set(\n", + " ignore_meas_id=True\n", + ") # Setting `ignore_meas_id=True` drops the noisy-identity gate from earlier" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now, we change backends! Before selecting an Infleqtion machine in CUDA-Q, we must first set our Superstaq API key, like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ['SUPERSTAQ_API_KEY'] = \"api_key\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we declare the type of execution we would like on Infleqtion's machine based on the keyword options specified:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "cudaq.reset_target()\n", + "\n", + "# Set the following to run on Infleqtion's Sqale QPU:\n", + "cudaq.set_target(\"infleqtion\", machine=\"cq_sqale_qpu\")\n", + "\n", + "# Set the following to run an ideal dry-run on Infleqtion's Sqale QPU:\n", + "# cudaq.set_target(\"infleqtion\", machine=\"cq_sqale_qpu\", method=\"dry-run\")\n", + "\n", + "# Set the following to run a device-realistic noisy simulation of Infleqtion's Sqale QPU:\n", + "# cudaq.set_target(\"infleqtion\", machine=\"cq_sqale_qpu\", method=\"noise-sim\")\n", + "\n", + "# Set the following to run a local, ideal emulation:\n", + "# cudaq.set_target(\"infleqtion\", emulate=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With that, we're all set! That simple change instructs our AIM circuits to execute on Infleqtion's QPU (or simulator). Due to the general queue wait time of running on hardware, we optionally recommend enabling the `run_async=True` flag to asynchronously sample the circuits. This will allow the cell to be executed and not wait synchronously until all the jobs are complete, allowing other classical code to be run in the meantime. When using `run_async`, an optional directory to store the job information can be specified with `folder_path` (this will be important to later retrieve the job results from the same directory)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Posting circuits associated with layer=('1:-9')\n", + "Posting circuits associated with layer=('1:-1')\n", + "Posting circuits associated with layer=('1:7')\n", + "Posting circuits associated with layer=('5:-9')\n", + "Posting circuits associated with layer=('5:-1')\n", + "Posting circuits associated with layer=('5:7')\n", + "Posting circuits associated with layer=('9:-9')\n", + "Posting circuits associated with layer=('9:-1')\n", + "Posting circuits associated with layer=('9:7')\n", + "\n", + "All circuits submitted for async sampling!\n" + ] + } + ], + "source": [ + "submit_aim_circuits(\n", + " device_circuit_dict, folder_path=\"hardware_aim_future_results\", shots_count=1000, run_async=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the above cell execution, all the circuits will post to execute on QPU. We can then return at a later time to retrieve the job results with the cell below:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Retrieving all circuits counts associated with layer=('1:-9')\n", + "Retrieving all circuits counts associated with layer=('1:-1')\n", + "Retrieving all circuits counts associated with layer=('1:7')\n", + "Retrieving all circuits counts associated with layer=('5:-9')\n", + "Retrieving all circuits counts associated with layer=('5:-1')\n", + "Retrieving all circuits counts associated with layer=('5:7')\n", + "Retrieving all circuits counts associated with layer=('9:-9')\n", + "Retrieving all circuits counts associated with layer=('9:-1')\n", + "Retrieving all circuits counts associated with layer=('9:7')\n", + "\n", + "Obtained all circuit samples!\n" + ] + } + ], + "source": [ + "aim_device_data = _get_async_results(circuit_layers, folder_path=\"hardware_aim_future_results\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "physical_energies, physical_uncertainties = aim_physical_energies(\n", + " data_ordering, aim_device_data[\"physical\"]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "logical_energies, logical_uncertainties = aim_logical_energies(\n", + " data_ordering, aim_device_data[\"logical\"]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Layer=(1, -9) has brute-force energy of: -18.251736027394713\n", + "Physical circuit of layer=(1, -9) got an energy of: -17.626499999999997\n", + "Logical circuit of layer=(1, -9) got an energy of: -17.69666562801761\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(1, -1) has brute-force energy of: -2.265564437074638\n", + "Physical circuit of layer=(1, -1) got an energy of: -2.1415\n", + "Logical circuit of layer=(1, -1) got an energy of: -2.2032104443266585\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(1, 7) has brute-force energy of: -14.252231964940428\n", + "Physical circuit of layer=(1, 7) got an energy of: -12.9955\n", + "Logical circuit of layer=(1, 7) got an energy of: -13.76919450035401\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, -9) has brute-force energy of: -19.293350575766127\n", + "Physical circuit of layer=(5, -9) got an energy of: -18.331\n", + "Logical circuit of layer=(5, -9) got an energy of: -18.85730052910377\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, -1) has brute-force energy of: -3.608495283014149\n", + "Physical circuit of layer=(5, -1) got an energy of: -3.476\n", + "Logical circuit of layer=(5, -1) got an energy of: -3.5425689231532203\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(5, 7) has brute-force energy of: -15.305692796870582\n", + "Physical circuit of layer=(5, 7) got an energy of: -14.043500000000002\n", + "Logical circuit of layer=(5, 7) got an energy of: -14.795918428433312\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, -9) has brute-force energy of: -20.39007993367173\n", + "Physical circuit of layer=(9, -9) got an energy of: -19.4715\n", + "Logical circuit of layer=(9, -9) got an energy of: -19.96524696701215\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, -1) has brute-force energy of: -5.260398644698076\n", + "Physical circuit of layer=(9, -1) got an energy of: -4.973\n", + "Logical circuit of layer=(9, -1) got an energy of: -5.207315773582224\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n", + "Layer=(9, 7) has brute-force energy of: -16.429650912487233\n", + "Physical circuit of layer=(9, 7) got an energy of: -15.182\n", + "Logical circuit of layer=(9, 7) got an energy of: -16.241375689575516\n", + "------------------------------------------------------------------------\n", + "Logical circuit achieved the lower energy!\n", + "------------------------------------------------------------------------ \n", + "\n" + ] + } + ], + "source": [ + "physical_energy_diff, logical_energy_diff = _get_energy_diff(\n", + " bf_energies, physical_energies, logical_energies\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As before, we use the same metric of comparing against the true ground state energies; however, this time, both the physical and logical circuits are fully exposed to real hardware noise. Yet, we expect the use of logical qubits afforded to us by the `[[4,2,2]]` code to achieve energies closer to the true ground state than the bare physical circuits (up to a certain error threshold). And indeed they do! Visually, we can plot the energy deviations of both the physical and logical circuits from the cell above and observe that the logical circuits are able to outperform the physical circuits by obtaining much lower energies, demonstrating the power of error detection and the beginning possibilities of fault-tolerant quantum computation: " + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAACIMAAAVkCAYAAABNJ02+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAB7CAAAewgFu0HU+AAEAAElEQVR4nOzdd3yN5/8/8NfJHrKQECKJGdTW2JGgqKqt9mxLKa0WbT9GUaVao0W1arQRmxpFbamYsYKYQURIgkRk73X//vBLvk7u+5ycmXMSr+fjcR6P5Dr3dV3vs+75vq9LJgiCACIiIiIiIiIiIiIiIiIiIiIqF0wMHQARERERERERERERERERERER6Q6TQYiIiIiIiIiIiIiIiIiIiIjKESaDEBEREREREREREREREREREZUjTAYhIiIiIiIiIiIiIiIiIiIiKkeYDEJERERERERERERERERERERUjjAZhIiIiIiIiIiIiIiIiIiIiKgcYTIIERERERERERERERERERERUTnCZBAiIiIiIiIiIiIiIiIiIiKicoTJIERERERERERERERERERERETlCJNBiIiIiIiIiIiIiIiIiIiIiMoRJoMQERERERERERERERERERERlSNMBiEiIiIiIiIiIiIiIiIiIiIqR5gMQkRERERERERERERERERERFSOMBmEiIiIiIiIiIiIiIiIiIiIqBxhMggRERERERERERERERERERFROcJkECIiIiIiIiIiIiIiIiIiIqJyhMkgREREREREREREREREREREROUIk0GIiIiIiIiIiIiIiIiIiIiIyhEmgxARERERERERERERERERERGVI0wGISIiIiJ6Q2VmZmLjxo348MMP0aRJE1StWhVWVlaQyWRyj759+8rVi4yMFC3j6elpkNdAys2bN0/0Wc2bN8/QYRGVS35+fqLfW1BQkKHDIiJ643h6eorWx5GRkYYOi5RYtGiR3OdVp04d5ObmlliPxyVUFryp+4hcF5Oxu3fvHszNzeW+o2fPnjV0WEQ6Z2boAIiISD0RERF4+PAhnjx5gpSUFGRkZMDCwgKOjo5wcnJClSpV0LRpU9jb2xs6VCKl0tLScPv2bURERODFixdIT0+HIAiwtbWFs7MzateujYYNG8LOzs7QoRKVS6tXr8a3336Lly9fGjoUIiIiIiJ6Q0VFRWHhwoVyZT/8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qBG++uorLF++HHPmzEF2drbcMmFhYejatSuCg4NRoUIFXb4MnZGa/qT451u4nLEngzRr1gzh4eFIS0srKvP399c6GaT4e+Th4QFBECSTgEg7165dE5X5+fmVfiBERERkFNQ9diIi0oWgoCCEhITIlY0bNw4mJpzVnoiISl+9evXg6+uLU6dOFZWtXbsWc+bMMdpzzkSq4t4VEZGB5eXloU+fPpKJIK6urjhz5gx++eUXjYYkk8lk6N27Ny5cuICAgABUrFhRFyGXOyYmJmjXrh1+//13PHr0CJ988onkSBXJycno3r27wtFbNLF7927RqCRVq1bFN998I1pWlRFEDE0QBAwZMgQPHz4UPVe5cmWcPn0as2fPLjER5HUWFhb4+uuvce7cOckpYW7duoUxY8ZoE7beREVF4cSJE6Ly5cuXi8oOHjyIFy9elEJUmrO1tcUHH3wgV3bw4EHExcVp3Obt27dFUwmNHj1a8jdI2ouPjxeVubm5GSASIiIiIiJ6U/38889y/5uZmeHDDz80UDRERETA+PHj5f5PTk7Gn3/+aaBoiHSHySBERAa2YMECXLhwQVTu5uaGs2fPom3btlr3IZPJMGrUKISGhqJDhw5at1eeOTs7448//sD+/fsls34TExPxwQcfIC8vTyf9SSV4DB8+HGPHjhVdDA8NDcXVq1d10q++/Pbbbzh+/Lio3NHRESdPntTqzsOWLVsiKCgITk5Ooud2796NzZs3a9y2vgQEBKCgoECurGXLlhg/fjzq1KkjV56bm4tNmzaVZngaGTt2rNz/eXl5Wr33xUcFkclkRpvcUx4kJyeLyqytrQ0QCRERERERvYkiIiLw77//ypX16NHDqKd/JSKi8m/AgAFwcHCQK1u5ciUEQTBQRES6wWQQIiIDevjwIX744QdRuampKXbv3o1atWrptD83NzcEBgZi6NChOm23PHr//fdx6NAhWFpaip4LCQnB6tWrte7j8ePH+O+//0Tlo0ePhru7Ozp16iR6zphHB4mPj8fMmTMln9uwYQMaNWqkdR8NGjTAxo0bJZ/78ssvkZqaqnUfuiIIAjZs2CAqHz16NABg1KhRoueM+fMt5OPjI0pk0TTu3NxcUSKJn58fatasqXF8pFxOTo6hQyAiIiIiojdYQECA6MLawIEDDRQNERHRK5aWlnj//fflyiIiInDmzBkD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8o8//lhvfSr6rezevVtvfapqx44dyMjIkCurWLGiaN7JgQMHiobsTUpKwj///KPvELVWfDqXxMREteLeuHEj8vLylLZZnt27dw+tWrXC0aNH1aqXnZ2NyZMn44cfftBTZKVv3bp1aNmyJU6ePKlR/ejoaIwYMQJfffWVaOotVT148ACtW7fGkSNH1KqXmZmJL774AlOmTNGo37Lk77//hre3N86ePatR/RcvXmD06NEYM2aM5BR5mlq1ahV69eqFZ8+eqVUvPDwcPj4+uHHjhs5iKY/i4uLw559/IjExUat2Hj9+jH79+uG7777TUWSvREZGwtvbGwcPHtSqnXPnzqFVq1YICQlRq15iYiKGDh2KZcuWadSvnZ0dvL295cqSk5Nx5coVldsIDAzU6LniTp48iYKCArmyTp06lTj9xMaNG3Hr1i2V+5GSnZ2NFStWwM/PD8+fP9eqrdcJgoAPP/wQ06dPR2ZmplZtHThwAE2aNJE8hlNFQkICvvjiCwwfPlyn68CyplGjRvjtt99E5cePH8fChQvVauvKlSuYPn26qLxnz5746quvVGrDWD7X06dPo3Hjxvjjjz9E+8fqePnyJR4/fqxxfZKXk5ODESNG4MMPP8TLly81auP06dN4++23FR4vayI9PR3du3fHzz//LFpvl2TDhg3o27evVt8zbR0+fFhU5ufnV/qBFBMdHY327dtjyZIlGv2eCwoKsG7dOrz99tu4e/euSnV8fHxEU+qdPn1arc+n+NTChfLy8nD69GmV25HaZ+jcubPK9YODg9GkSROsW7cO+fn5KtcrlJGRgfnz56NHjx5ISUlRu76U7OxsvP/++1i8eLFBv/PaevbsGXx8fODv76/x8W6h/Px8o3gvbt++jXbt2uHixYtq1UtJScGYMWPwzTffaNW/sWz/yxpjOHdTnK6OB4vr1KmTqOzQoUM67YOoNHGiayIiA3j27BmuX78uKvfz8yszczm+SWQyGfr27Yvly5fLlefn5+P06dPo37+/Wu0lJydLHnBIJX74+fnBw8ND7qReQUEBAgICMHPmTLX61Zfc3FzJExCenp5o37693vpt3749PD09ERkZKVd+/PhxFBQUlMp8oopIJfsMHToUFhYWcmUVKlRA//79sWnTJlH9IUOG6DVGbfXt2xdOTk5yFwj9/f0xePBgler7+/vL/V+/fn20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Lfrf1NQU4eHhWo+EoGtZWVmIiopCSkoKAMDW1hY1atTQy5335VVKSgqePn2KjIwMCIJQtD51dnbmMYOGEhMT8fLlS6SlpSE/P7/oONnZ2ZnbBy0Zw/a/LDLkuRtd2LJli2j6yn379qF3794GiohId5gMQkREREZp69atGDFihOgOnAoVKuC///5TONw5EZGhvKnJIERERERE6oqPj0etWrWQmppaVDZp0iSsWrXKgFEREdGbRhAENG3aFDdv3iwqa926NS5cuGDAqIh0h2lsREREZJSGDRuGJUuWiMrT0tLw3nvv4d69ewaIioiIiIiIiIi0VblyZXz55ZdyZX/99ZfCKUWIiIj04eDBg3KJIACwcOFCA0VDpHtMBiEiIiKjNW3aNNHJIeDVHUTdunVDdHS0AaIiIiIiIiIiIm1NmzYNVapUKfo/MzMTy5YtM2BERET0pime+NGtWzd06dLFQNEQ6R6TQYiIiMioLVu2DEOGDBGVP3nyBN27d0dCQoIBoiIiIiIiIiIibdjb2+Onn36SK1u5ciViYmIMFBEREb1J9uzZIzcdjLm5OVauXGnAiIh0j8kgREREZNRkMhkCAgLQuXNn0XN37txBz549kZGRYYDIiIiIiIiIiEgbo0aNQvv27Yv+z8zMxNy5cw0YERERvQny8vIwY8YMubKpU6fCy8vLQBER6YeZoQMgIiIiKomFhQX27t2L8ePHIykpSfT8unXrMGXKlNIPjIiIiIiIiIg0JpPJsG7dOuzYsaOozMzMDLm5uTA3NzdgZEREVJ49efIEQ4cOLfpfJpNh+vTpBoyISD9kgiAIhg6CiIiIiIiorBszZgwCAgLkyvz9/TFmzBjDBERERERERERERERvLE4TQ0RERERERERERERERERERFSOMBmEiIiIiIiIiIiIiIiIiIiIqBxhMggRERERERERERERERERERFROSITBEEwdBBEREREREREREREREREREREpBscGYSIiIiIiIiIiIiIiIiIiIioHGEyCBEREREREREREREREREREVE5YmboAIiMSVZWFm7evAkAcHZ2hpkZfyJERERERERERERERERERKQ/eXl5ePHiBQCgcePGsLKy0rpNXukmes3NmzfRqlUrQ4dBRERERERERERERERERERvoEuXLsHb21vrdjhNDBEREREREREREREREREREVE5wpFBiF7j7Oxc9PelS5fg6upqwGiIiIiIiIiIiIiIiIiIiKi8e/bsWdEMFq9fs9YGk0GIXmNm9n8/CVdXV7i5uRkwGiIiIiIiIiIiIiIiIiIiepO8fs1aG5wmhoiIiIiIiIiIiIiIiIiIiKgcYTIIERERERERERERERERERERUTnCZBAiIiIiIiIiIiIiIiIiIiKicoTJIERERERERERERERERERERETlCJNBiIiIiIiIiIiIiIiIiIiIiMoRJoMQERERERERERERERERERERlSNMBiEiIiIiIiIiIiIiIiIiIiIqR5gMQkRERERERERERERERERERFSOMBmEiIiIiIiIiIiIiIiIiIiIqBxhMggRERERERERERERERERERFROcJkECIiIiIiIiIiIiIiIiIiIqJyhMkgREREREREREREREREREREROUIk0GIiIiIiIiIiIiIiIiIiIiIyhEmgxARERERERERERERERERERGVI0wGISIiIiIiIiIiIiIiIiIiIipHmAxCREREREREREREREREREREVI4wGYSIiIiIiIiIiIiIiIiIiIioHGEyCBEREREREREREREREREREVE5wmQQIiIiIiIiIiIiIiIiIiIionKEySBERERERERERERERERERERE5QiTQYiIiIiIiIiIiIiIiIiIiIjKETNDB0BE8goKCpCWlobU1FTk5uaioKAA+fn5hg6LiIh0yNTUFKamprC0tISDgwOsrKwgk8kMHRYREREREREREREREZUTTAYhMgKCICA1NRWpqalIS0tDQUGBoUMiIiI9ysvLAwBkZGQgMTERFhYWcHBwgKOjI8zMuHtGRERERERERERERETa4dUGIgMTBAHPnj1DcnKy5PMymQympqalHBUREelTfn4+BEEo+j8nJwcvXrxAUlISPDw8YG5ubsDoiIiIiIiIiIiIiIiorGMyCJEBSSWCmJqaws7ODnZ2drCxsYGJiYkBIyQiIn3Jz89HamoqkpOTkZGRAQDIzc1FVFQUPDw8mAhIREREREREREREREQaYzIIkYFIJYK4urrCwcEBMpnMgJEREVFpMDU1haOjIxwdHZGTk4MnT54gNzcX2dnZiIqKgru7OxMCiYiIiIiIiIiIiIhII7zCQGQghXeDF6pevTocHR2ZCEJE9AaysLCAu7t70WggmZmZSExMNHBURERERERERERERERUVjEZhMhAUlNTi/52dXWFvb29AaMhIiJDs7CwgJubW9H/aWlpBoyGiIiIiIiIiIiIiIjKMiaDEBlAQUFB0UU+U1NTODg4GDgiIiIyBjY2NrCwsAAAZGRkID8/38ARERERERERERERERFRWcRkECIDSEtLQ0FBAQDAzs6OU8MQEVEROzu7or85OggREREREREREREREWmCySBEBvD6FDGvX/QjIiKqUKFC0d9MBiEiIiIiIiIiIiIiIk0wGYTIAHJzc4v+trGxMWAkRERkbKytrYv+fn17QUREREREREREREREpComgxAZQOEUMTKZDCYm/BkSEdH/kclkRdOHFW4viIiIiIiIiIiIiIiI1MGr0EQGkJ+fDwAwNTU1cCRERGSMCrcPhdsLIiIiIiIiIiIiIiIidTAZhIiIiIiIiIiIiIiIiIiIiKgcYTIIERERERERERERERERERERUTnCZBAiIiIiIiIiIiIiIiIiIiKicsTM0AEQ0Ztj9ZojWL32iM7bnTj+XUz85F2dt0tEREREREREREREREREVBYxGYSISk1qWiaePU/US7tERERERERERERERERERPQKk0GIqNTYVbCGa1Unhc8XFAiIjUuSK6vi4ggTE1mJ7RIRERERERERERERERER0StMBiGiUjPxE+XTucS/TEGDJp/JlQWd+B6VK9nrOzQiIiIiIiIiIiIiIiIionLDxNABEBEREREREREREREREREREZHuMBmEiIiIiIiIiIiIiIiIiIiIqBxhMggRERmdDRs2QCaTyT2CgoIMHVa5M2/ePNH7HBkZaeiwjA6/j0REREREREREREREVNaYGToAIiIyXjKZTOVlTUxMYG9vD0dHR7i4uKBly5Zo1aoVevTogSpVqugxSiIiIiIiIiIiIiIiIiJ6HUcGISIinSgoKEBSUhIiIyNx6dIlrF69GmPHjoW7uzuGDx+O27dvGzpEIiIiIiIiIiIiIiIiojcCk0GIiEivcnJysHXrVrRs2RLLly83dDhERERERERERERERERE5R6niSEiIrXY2dnBxEScS1hQUIDU1FSF9bKzs/Hll18iPj4eCxYs0GeIRERERERERERERERERG80jgxCRERquXHjBpKSkkSPlJQU5ObmIiwsDKtWrULdunUl6y9cuBBbt24t5aiJiIiIiIiIiIiIiIiI3hxMBiEiIp0xMzODl5cXJk2ahLt372Lq1KmSy33zzTfIzs4u5eiouHnz5kEQBLmHp6enocMiIiIiIiIiIiIiIiIiLTEZhIiI9MLU1BTLli3D+PHjRc9FR0djw4YNpR8UERERERERERERERER0RuAySBERKRXy5YtQ8WKFUXl//77rwGiISIiIiIiIiIiIiIiIir/mAxCRAaXk5OHfQcuYdbcLaLn+n3wI6ZM+xP7DlxCTk6eAaIjbVWoUAEjR44UlZ86dQr5+fkGiIiIiIiIiIiIiIiIiIiofDMzdABE9ObKzc3DH+uOYvXao3jxIllymbB7MQi7F4Ot20/DxcUBE8Z1x4Rx3WFuztVXWeLn54cVK1bIlaWmpiIuLg6urq5atR0WFoarV6/i6dOnyMnJQeXKleHq6ooOHTrAyclJq7aNRUpKCm7evIkHDx4gOTkZqampMDc3h42NDSpVqgRPT0/UqVMHLi4uhg61yP3793Hv3j3Ex8cjPj4eeXl5sLe3h6urKxo2bIi6devC1NRUqz6ysrKK+nnx4gVSUlIgk8lQsWJFVKpUCY0bN0bdunV19IqIiIiIiIiIiIiIiIjKDl5NJSKDCLsXjUlT1uLGzccq14mLS8b8hTvxz/6L+G3FeNT3ctNjhKRL7u7ukuXx8fEaJYPk5ORgzZo1WLlyJcLDwyWXMTU1RYcOHTB//nx07NhRpXbff/99HDx4UK4sNDQUTZo0UTvG1w0dOhTbt2+XKztz5gw6dOigsE52djY2bNiATZs24fz58xAEocR+PDw80K5dO/Tt2xc9e/aEra2t0uXnzZuH7777Tq7s0aNH8PT0LLEvKZcuXcLq1atx4sQJREdHK13W3t4enTt3Rt++ffHBBx/AxsamxPYFQcDZs2dx8OBBBAUFISQkBHl5ykcMqlKlCt577z1Mnz4dDRs2VOv1EBERERERERERERERlVWcJoaISt2lyw/wXp8FaiWCvO7Gzcd4r88CXLr8QMeRkb7Y29tLlqempqrd1t27d9GiRQt8/vnnChNBACA/Px+nTp2Cr68vJk+ejIKCghLbnjhxoqhs7dq1asf4uvj4eOzdu1eurGHDhkoTQc6cOYNGjRphwoQJOHfunEqJIADw+PFjbNu2DYMHD8bkyZO1ilsdt27dwnvvvYfWrVtjw4YNJSaCAK9GO/nnn38wZswYVKtWDc+fP1e6/NatW+Hu7o6OHTvip59+wsWLF0tMBAGA2NhY+Pv7o1GjRhgzZgwyMjJUfl1ERERERERERERERERlFZNBiKhUhd2LxpCRy5CamqlVO6mpmRgychnu3Y/RUWSkT8nJ0tMAOTg4qNXOlStX0LZtW9y+fVuter/99hvGjRtX4nI9evSAh4eHXNmWLVuQman59zUgIADZ2dlyZePHj1e4/OHDh9GtWzeliS6qUDWBRFu7d+9GmzZtcPjwYY3bSE5ORlZWltJlLl26pFKSiSKCICAgIADt27dHbGysxu0QERERERERERERERGVBZwmhohKTW5uHiZNWat1Ikih1NRMfPr5Ghw5MAfm5lydGbNHjx5JlleuXFnlNqKiojB16lS5xBJPT0907twZbm5usLW1RVxcHM6ePYtLly6JkiH++usv9O7dG3369FHYh4mJCT755BPMnDmzqCwpKQk7duzAmDFjVI71devWrZP738rKCqNGjZJc9sWLFxgxYoRkYkT16tXRvn171K5dG/b29jA1NUVKSgpevnyJO3fu4MaNG0hMTNQoRk39/vvvmDx5smTiiampKby9vdGyZUs4OzvD2toaSUlJiImJwZUrVxAWFqbSaC2KmJiYoFatWmjUqBFq1aoFe3t72NraIj09HXFxcQgNDZUcPeT69esYPnw4jh07BhMT5sQSEREREREREREREVH5xKunRFRq/lh3VOOpYRS5cfMx/lh3FJ992lOn7ZJunTx5UlTm6OgIZ2dnldv48ssv8fLlSwBA48aNsXTpUnTr1k1y2eDgYIwYMQIRERFy5dOmTUPv3r0hk8kU9vPRRx9h7ty5yM3NLSpbu3atRskgp06dwr179+TKBg4cCCcnJ8nlly1bhoSEBLmyOnXq4LffflP4WgsJgoDLly/jwIED+Ouvv9SOVV2nT5/GlClTRIkgNjY2+OKLLzB16lRUqlRJYf24uDjs2bMH/v7+uHTpkkp9mpqaolevXujfvz/ee+89pe0X9vHbb79h8eLFcgk2gYGBWLlyJb744guV+iUiIiIiIiIiIiIiIipreEssEZWKnJw8/LHuqF7a/mPdUeTm5pW8IBlESkoKNm/eLCr38/NTa2SGwkSQ9957D8HBwUqTI9q2bYtTp06hYsWKcuUPHz5EUFCQ0n5cXFzQv39/ubLg4GDcunVL5VgLrV27VlT2ySefKFx+165dcv87Ozvj7NmzJSaCAIBMJkOrVq3w/fff4/Hjx/jmm2/UjldVSUlJGDRokGjUDXd3d1y5cgULFy4sMVHDxcUFEyZMwMWLFxEYGAhHR0ely/fr1w8RERHYu3cvRo4cWWL7hX189913OHv2rOi78PPPP4viJyIiIiIiIiIiIiIiKi+YDEJEpeLw0auIi0sueUENxMUl49CRq3ppm7Q3efJkpKSkiMp79eqldlteXl7YuXMnbG1tS1zWzc0N8+fPF5Xv3bu3xLoTJ04UlUkldiiTkJCA3bt3y5U1bNgQHTp0kFw+JycHDx8+lCsbO3YsqlSpola/AGBmZoYGDRqoXU9Vq1atQmxsrFxZxYoVcfbsWY367dy5c4nJIL6+vnB3d1e7bQBo2bKlaLqeqKgoHDhwQKP2iIiIiIiIiIiIiIiIjB2TQYioVPwXdFOv7Z88pd/2SX3Z2dn45JNPsGnTJtFznp6eGDlypNptrly5UqVEkEIjRoyAlZWVXFlISEiJ9Xx9fdGwYUO5ss2bN8tNNVKSgIAAZGdny5WNGzdO4fLx8fGistq1a6vcX2nJyMjAihUrROVr1qxBjRo1DBCRavr37486derIlUlNX0RERERERERERERERFQeMBmEiEpF6I3IMt0+laygoAAJCQm4fPkyFi1ahDp16kiOpiGTybBs2TKYm5ur1X79+vVVmi7ldQ4ODmjWrJlc2Y0bN1SqO2HCBLn/ExMTsXPnTpX7Lj4ShZWVFUaNGqVw+QoVKojKHj16pHJ/peXo0aOixJUmTZpg4MCBBopIdb6+vnL/X7hwwUCREBERERERERERERER6ReTQYioVDyMeKbf9h8+12v79H9q1qwJmUwmepiamqJSpUpo1aoVZs6ciejoaMn6CxcuRP/+/dXut2vXrhrF+9Zbb8n9n5aWhpycnBLrjRo1CjY2NnJlxRM8FDl79izu3r0rVzZw4EBUrFhRYR17e3u4urrKla1Zswbh4eEq9VlagoKCRGXFE2eMVdWqVeX+v3PnjoEiISIiIiIiIiIiIiIi0i8mgxBRqcjOztNr+1nZuXptn7Rna2uLtWvXYsaMGRrVb9GihUb1nJycRGXJyckl1nNwcMDQoUPlyqSSPKRIjYgyfvz4Euv17t1b7v/ExES8/fbbWLhwIZ49029ClapOnz4tKuvUqVOpx5GYmIiAgABMmTIFnTt3Rq1ateDs7AwrKyvJZCWZTIaFCxfKtZGeno7cXK47iIiIiIiIiIiIiIio/GEyCBGVCktLM722b2Wp3pQjVHpsbW0xbtw4hIaGYty4cRq3U7lyZY37Ly4jI0OluhMnThSVSSV6vC4xMRG7du2SK2vQoAF8fHxK7O+bb74RxZucnIzZs2ejevXqaNOmDWbOnInDhw8jKSmp5BegBxEREXL/Ozg4wMvLq9T6v3PnDvr374+qVatizJgxWLlyJU6ePIlHjx4hPj4e2dnZarVnqPeRiIiIiIiIiIiIiIhIn/R7dZaI6P+rXcsVt+880V/7tauWvBDphJ2dHUxMxLmEJiYmsLOzg6OjI1xcXNCiRQu0atUK77zzDhwcHLTut0KFClq3UUgQBJWWa9myJby9vXH58uWiso0bN+LHH3+EpaWlZJ1NmzYhMzNTrkyVUUGAV1PwbN26FYMGDRIlNQiCgIsXL+LixYtYtGgRZDIZGjduDD8/P3Tt2hXdunWDhYWFSv1oKjc3FykpKXJlVatWhUwm02u/hebPn4/vv/8eeXm6G2lI1cQgIiIiIiIiIiIiIiKisoTJIERUKpo28dRrMkjTJp56a5vk3bhxA56enoYOo9RMnDhRLhkkISEBu3btwvDhwyWXX7dundz/VlZWGDVqlMr99e7dG+fPn8enn36KixcvKlxOEATcuHEDN27cwMqVK+Hk5ISRI0fim2++QbVq1VTuTx0JCQmiMkdHR730Vdy0adPw888/q7SsmZkZrKysYGpqKleelZUlmWRDRERERERERERERERU3nCaGCIqFZ39Guu1/U6++m2f3lxDhgwRJTwomirm/PnzuHXrllzZwIEDUbFiRbX6bNGiBS5cuIDjx49jxIgRKiVcJCYmYuXKlahduzZWrVqlVn/G7siRI5KJINbW1hg+fDjWrFmDixcvIjo6Gnl5ecjNzUVqaiqSkpLkHv/73/8MED0REREREREREREREVHp48ggRFQqenRvARcXB8TFJeu8bRcXB7z3bgudt0sEvEo4GD16NFasWFFUdvr0ady7dw9eXl5yy0oliag6RYyUd955B++88w4KCgpw/fp1nD59GmfPnsXZs2cRGxsrWScrKwufffYZYmNj8f3332vctxSppJakpCSd9iFl2rRporL+/ftj3bp1aiXapKen6zIsIiIiIiIiIiIiIiIio8WRQYioVFhYmGHCuO56aXvCuO4wN2duG+nPhAkTRGXFEz+Sk5Oxc+dOubIGDRrAx8dH6/5NTEzQokULfPHFF9i1axeeP3+OsLAw/Pzzz2jTpo1knQULFiA4OFjrvl9nbm4Oe3t7ubLY2Fi9TrVy+/Zt3LlzR66sbdu22Llzp9ojrkhNc0NERERERERERERERFQeMRmEiErNhHHd0aSxh07bbNrEExPHv6vTNomKq1+/Pjp16iRXtnHjRmRnZxf9v2nTJmRmZsoto82oICXx8vLCl19+ieDgYJw7dw61a9cWLbN06VKd91u8n6SkJNy/f1/n/RQKDAwUlX3zzTcwNTVVuy19xklERERERERERERERGRMmAxCRKXG3NwMv60YDzs7a520Z29vg99WjIeZmfoXhYnUNXHiRLn/4+PjsXfv3qL/161bJ/e8lZUVRo0aVSqxtWvXDkeOHIGFhYVc+YkTJ3TeV8eOHUVlJ0+e1Hk/hZ4+fSoqa9eundrtZGdn4/Lly7oIiYiIiIiIiIiIiIiIyOgxGYSISlV9Lzds3zRN64QQe3sbbNs4FV71qusoMiLl+vbti6pVq8qVFU4Vc/HiRdy4cUPuuQEDBqg9jYk26tSpgw4dOsiVpaSkICkpSaf9FB8hBQD++OMPnfbxOqmpXRwdHdVuZ+fOnXIjuRAREREREREREREREZVnTAYholLXyrsuDu//VuMpY5o09sChfbPRyruujiMjUszc3BwfffSRXFlQUBAePHhQlBTyuk8++aS0Qivi4uIiKsvJydFpH927dxf1ExoaKjdKii7Z2dmJyp49e6ZWG3l5eViyZImuQiIiIiIiIiIiIiIiIjJ6TAYhIoPwqlcdRw7MwZxZg+Di4qBSHRcXB8yZNQhHDszhiCBkEOPHj4eJyf9tOgVBwLJly7Bjxw655Ro0aAAfH5/SDg937tyR+9/c3BzOzs467cPKygpTpkwRlY8fPx4xMTE67QsAqlcX/9YPHDigVhvz5s3DzZs3dRUSERERERERERERERGR0WMyCBEZjLm5GT77tCeuX/oZ6/+YhAH92oqWaVDfDcOHdsT6Pybh+qWf8dmnPWFubmaAaIkAd3d39OzZU65szZo1SE9PlysbP3682m0fPHgQQ4cOxeXLlzWKbefOnaKpatq0aQOZTKZRe8pMmjQJrq6ucmXx8fHw8fHBvXv31G7v1KlTCqez8fPzE5UtWLBA5cSTn3/+GT/88IPaMREREREREREREREREZVlTAYhIoMzNzdDn16tsOC7YaLn9uz8BsuXfoQ+vVoxCYSMwsSJE5U+b2VlhVGjRqndbm5uLrZv345WrVrh7bffxo8//oj79++XWC81NRXff/89hg8fLnruww8/VDsOVTg4OGDHjh0wM5P/TT569AgtW7bEt99+i4SEBKVtvHz5EuvXr0fbtm3h5+enMBmkefPmqF+/vlzZ8+fP0bFjR5w6dUph++Hh4RgwYACmTZsGQRAAQJTAQkREREREREREREREVF7xyioREZEaunfvjpo1a+LRo0eSzw8YMAAVK1bUqo+QkBCEhIRgxowZqFy5Mpo3bw4vLy84OTnBwcEBOTk5ePHiBW7duoUzZ84gKytL1Iavry9Gjx6tVRzK+Pj4YPny5fjss8+Kki0AID09HQsWLMCiRYvQunVrtGjRAs7OzrC2tkZycjJiYmJw9epV3LlzB3l5eSX2I5PJsGDBAgwcOFCuPCIiAn5+fmjSpAl8fX1RrVo1FBQU4Pnz5zh//jyuXr0qF5ePjw98fX2xYMEC3b0JRERERERERERERERERorJIERERGowMTHB+PHjMWPGDMnnP/nkE532Fx8fj+PHj+P48eMq13n77bexc+dOvUwR87pJkybB2dkZY8aMQWZmptxz+fn5OH/+PM6fP691PwMGDMBnn32GX3/9VfTcjRs3RNPjFPfWW29h7969kvWJiIiIiIiIiIiIiIjKI04TQ0REpKYPP/wQFhYWovIGDRrAx8dHozYrV64MJycnreIyMzPD5MmTcfLkSbi4uGjVlqoGDRqE8+fPo1OnThq34ezsDBsbG6XLLF++HDNmzFA7waVPnz44d+4cKlWqpHF8REREREREREREREREZQ2TQYiIiNTk4uKCXr16icrHjRuncZsdOnTAixcvcOrUKcycORO+vr4lJkgUcnd3x/Tp03Hr1i38+uuvqFChgsZxaKJZs2b477//8N9//2HIkCGoXLlyiXUqVqyIQYMGYceOHYiOji4xecXExAQ//PADzp07h/fffx+mpqYKlzUzM8M777yDgwcP4p9//oGDg4Par4mIiIiIiIiIiIiIiKgskwmCIBg6CCJjER0djRo1agAAoqKi4Obmppd+Hjx4gLy8PJiZmaFu3bp66aMsin+ZggZNPpMru3vjV1SuZG+giIgUa9iwIe7evVv0v5WVFWJiYlCxYkWd9ZGfn4+IiAiEh4cjOjoaKSkpyMjIgI2NDezt7eHm5oamTZuiWrVqOutTFwoKChAaGoqIiAjEx8fj5cuXMDMzg52dHapXr44GDRqgdu3aMDHRPCc1JSUF586dw+PHj5GQkAATExM4OTmhTp068Pb2hr192V5vcDtBRERERERERERERPTm0Md1ajOtWyAiInrDnD9/Xi4RBAAGDBig00QQADA1NUXdunXLXDKAiYkJmjdvjubNm+utD3t7e/To0UNv7RMREREREREREREREZVlnCaGiIhITX/88YeobPz48QaIhIiIiIiIiIiIiIiIiEiMySBERERqiIuLw99//y1X1qhRI3Ts2NFAERERERERERERERERERHJYzIIERGRGpYsWYKsrCy5skmTJhkoGiIiIiIiIiIiIiIiIiIxJoMQERGp6Nq1a1ixYoVcmYuLC0aNGmWgiIiIiIiIiIiIiIiIiIjEmAxCRERUgufPn2PVqlXo2rUrcnNz5Z773//+BxsbGwNFRkRERERERERERERERCRmZugAiOjNsXrNEaxee0Th8wUFgqjM751vYWIiU9ruxPHvYuIn72odH1GhrVu34tNPPwUAZGdni6aFKdSwYcOi5YiIiIiIiIiIiIiIiIiMBZNBiKjUpKZl4tnzRLXqxMYlqdQukS7l5OQgOTlZ6TI2NjbYuHEjLC0tSykqIiIiIiIiIiIiIiIiItUYVTJIbGws7t+/j8jISERFRSE1NRXp6enIy8uDjY0NbG1t4eLiAg8PD9SsWRP169eHqampocMmIhXZVbCGa1UnvbRLVJpcXFywbds2tGzZ0tChEBEREREREREREREREYkYNBkkPDwchw8fRlBQEC5fvoyYmBi16ltaWqJp06Zo3bo1unfvjs6dO/MObSIjNvETTudCZZOpqSmcnJzQsGFD9OrVCx999BGcnHSf2ERERERERERERERERESkCzJBEITS7PDRo0fYuHEjtm7divDw8KJyTcOQyWRFf1tZWaFr164YNWoUevXqBXNzc63jpTdLdHQ0atSoAQCIioqCm5ubXvp58OAB8vLyYGZmhrp16+qlDyIiKru4nSAiIiIiIiIiIiIienPo4zp1qY0MsnfvXqxYsQJnzpwBIE7+eD2pQ12FbWVmZuLAgQM4cOAAnJycMHbsWHz++edFbxoRERERERERERERERERERFReWeiz8bz8vLwxx9/oG7duhg4cCDOnDkDQRAgCAJkMpnco7Bc3QcAyXYSEhLw888/o3bt2hg6dChu376tz5dKREREREREREREREREREREZBT0MjKIIAjYtGkTvvvuO0RGRoqSNgqXKeTs7IymTZuicePG8PDwgJubG1xdXWFjYwNra2uYmZkhMzMTmZmZSEhIQHR0NGJiYhAWFobQ0FDcv38feXl5Re293kdeXh527tyJXbt2YejQoZg3bx5q1aqlj5dNREREREREREREREREREREZHA6TwY5f/48Jk+ejNDQULkkEOD/EkCcnZ3Ro0cPdOrUCZ06dYK7u7tWfWZnZyM4OBgnT57EiRMncOHCBVHf+fn52LJlC3bu3ImpU6di9uzZsLGx0apfIiIiIiIiIiIiIiIiIiIiImMjE14fokNLo0aNwpYtWwCgaCqYwuYdHBwwdOhQfPDBB/D19YWJif5mqHn27Bn27NmDrVu3Ijg4GIB8QopMJoObmxs2b94MHx8fvcVBJUtOTsb58+cRHh6OlJQUWFpaonr16nj77bdRt27dUo8nOjoaNWrUAABERUXBzc1NL/08ePAAeXl5MDMzM8jrJCIi48btBBERERERERERERHRm0Mf16l1OjLI5s2bi5IugFeJF61bt8bEiRMxaNAgWFlZ6bI7hVxdXTFp0iRMmjQJt2/fxtq1a7FhwwakpqYWJahER0fj5MmTek0GEQQB4eHhuHTpEi5fvoxLly7h2rVryMrKEi1X2jw9PfH48WOt2vD398eYMWM0qhsaGor58+fjwIEDyM3NlVzmrbfewvTp0zF69Gi57xUREREREREREREREREREREppvNpYoBXyQ3du3fHjBkz0LFjR310obK33noLK1aswPz587Fq1SqsXLkSL1680Ft/aWlpWLRoES5fvozLly8jKSlJb32VVYsWLcKcOXOQl5endLnbt29j7NixCAgIwM6dO+Hs7FxKERIREREREREREREREREREZVdOp+rxcfHBxcuXMDhw4cNngjyOgcHB8yaNQuRkZH4/vvvYWdnp5d+4uPj8cMPP+D48eNMBJHw1VdfYebMmZKJIHZ2dpLTBwUFBcHX1xcvX74sjRCJiIiIiIiIiIiIiIiIiIjKNJ2ODPLvv//ivffe02WTOmdtbY1Zs2ZhwoQJiIiIMHQ4RmPBggWoVKmSWnXatm2r1vJbtmzB0qVL5co8PT0xa9YsDBw4EI6OjsjJycGlS5fw448/4uDBg0XL3b17F8OGDcORI0c4ZQwREREREREREREREREREZESOk0GMfZEkNdVqlRJ7eQHTdja2qJFixbw9vaGt7c3wsPD8e233+q9X3UNHz4cnp6eems/PT0dU6dOlStr3rw5jh49Kjf9i4WFBTp06IB///0Xs2bNwg8//FD03LFjx7B7924MHDhQb3ESERERERERERERERERERGVdTpNBiHAxsYGEyZMKEr+aNiwIUxNTYue37Bhg+GCM6AVK1YgLi6u6H8bGxvs2rVLLhGkuIULFyIkJARHjx4tKpszZw769+8vOZ0MERERERERERERERERERERMRlE51xcXLB69WpDh2FU8vLy8PPPP8uVTZs2DbVq1Sqx7qpVq1CvXj0IggDg1XQx+/fvR9++ffURKhERERERERERERERERERUZnH4RVI706fPo2XL18W/W9iYoJx48apVLdOnTro1KmTXNnevXt1Gh8REREREREREREREREREVF5opdkkHfffRe7du1Cbm6uPpqnMmbfvn1y/7dt2xY1atRQuf6QIUPk/j948CDy8/N1EhsREREREREREREREREREVF5o5dkkGPHjmHw4MGoVq0apk6dips3b+qjGyoj/vvvP7n/27dvr1b9du3ayf3/8uVLXL9+XduwiIiIiIiIiIiIiIiIiIiIyiW9ThPz8uVLrFixAs2aNUOrVq2wdu1apKam6rNLMjL5+fm4f/++XFnr1q3VaqNhw4awt7eXK7t7967WsREREREREREREREREREREZVHZvpsXCaTQRAEAMCVK1cQEhKCqVOnYsCAAfjwww/h6+urz+5JTZGRkbh79y5evHgBmUyGSpUqoUqVKmjSpAnMzc01ajMiIgI5OTlyZbVq1VKrDZlMBk9PT9y4caOoLCwsTKN4iIiIiIiIiIiIiIiIiIiIyju9JoMAry7kA4AgCBAEARn/j737Do+qWt8+fu8kEwghjRKCVINUpQuIdNQTBBFFUNQjRQSponKO8hNRRFQ8VlSkSVVUEAtKVQQEpRcFwSC9JoSSSnqy3z94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LY+JadCggWn7/PnzdqThdevXr9cVV1yhF154ocBGEOnPu2NMmTJFzZo106JFi0oxQyklJUUjRozQkCFDCmwEkf68s8nPP/+snj176pFHHlFWVpbHc77yyivq2LGj5s6dW2AjiCRt375dd999t/r06aOEhASP5wMAAAAAAAAAAAAAoCyxpRmkU6dOkuS828OBAwfsSMOr1qxZo969e+vw4cMur4WHh6t8+fIu+8+ePavBgwfru+++K40UdfHiRQ0cOFBz5sxxec3hcCgqKirfcW+//bZuv/12GYbh9pz/93//p6eeeirfZpJKlSopKMj1W3LZsmXq2bOnzpw54/Z8AAAAAAAAAAAAAACUNbY0g9StW1ddu3Z1NhMsXrzYjjS8JiEhQUOHDlVycrJzX0hIiB599FHt3r1bqampSklJUVxcnJ599llFREQ4j8vKytJtt92mPXv2eD3Phx9+WL/++qtp39VXX61FixYpJSVF58+fV2JiombPnq2WLVuajps9e7ZeeeUVt+abNWuW/vWvf5n2NWzYUB9++KHOnTunxMREXbx4Ub/99psGDRpkOm7nzp3661//6lEDCgAAAAAAAAAAAAAAZYktzSDSn3eIkCTDMLRp0yYtX77crlQsN2HCBJ04ccK5HR4ernnz5unNN9/UZZddpqCgIDkcDjVo0EAvvPCCfvnlF1WpUsV5fHJysh577DGv5rhu3Tp99NFHpn0jR47UsmXL1K9fP+edSypVqqQRI0Zo9erV6tu3r+n4F154QUePHi3WfCkpKS7n1K5dO61du1Z/+9vfVLlyZUlSWFiYrr76ai1YsEBPPfWU6fiffvpJ33zzjTunCQAAAAAAAAAAAABAmWNbM8jQoUN1/fXXO7fvv/9+nT9/3q50LBMXF+fSZPH888+bzjWvLl266N133zXt++GHH/T77797JUdJevrpp03brVq10rRp0xQcHJzv8REREZo9e7ZiYmKc+9LT0zVx4sRizTdlyhSdOnXKuV2hQgV9/fXXqlGjRoFjXnrpJfXr18+0b/z48crJySnWnAAAAAAAAAAAAAAAlEW2NYNI0syZM3XFFVfIMAzt3r1bAwYM0LFjx+xMqcTefPNNZWRkOLcbNWqkv//970WOu/XWW3X11Veb9r322muW5ydJmzZt0s8//2za99Zbbyk0NLTQcVWqVNGLL75o2vfxxx8rISGh0HFZWVmaPHmyad/f//53NW7cuMhc33nnHTkcDuf2zp079d133xU5DgAAAAAAAAAAAACAssrWZpDIyEgtX75cV199tQzD0Nq1a9W6dWtNnDjR9JgVf/Ltt9+atkeNGqWQkJBijb333ntN2z/99JNSU1OtSs1p3rx5pu2mTZuqT58+xRp7yy23qFKlSs7trKwsLViwoNAxv/76q86cOePcDgoK0ujRo4s1X5MmTdS7d2/Tvrz5AwAAAAAAAAAAAACA/ylel4IX3HPPPc5/N2jQQOvXr1d6errOnTunCRMmaMKECYqNjVXTpk1VtWrVIu9aURCHw6Hp06dblXahNm3apMOHD5v23XzzzcUef+ONN+qee+5RVlaWJOnixYv66aefNGTIECvT1Pz5803bI0aMKPbYiIgIDR48WF988YUp3t13313s+a688krVq1ev2HPecsstWrJkiXP7hx9+UHZ2doGPtAEAAAAAAAAAAAAAoCyzrRnk008/NT3+I5fD4ZBhGJKkffv2af/+/R7PYRhGqTaDXNqwIEk1a9ZUkyZNij2+QoUKatu2rdavX+/c98svv1jaDHL69Glt3brVtO+qq65yK0a3bt1MzSB5zzuvvK97Mt+lzpw5o82bN6tDhw5uxQEAAAAAAAAAAAAAoCyw9TEx0p8NG7nNH7kcDofzI/d1dz/ssGPHDtN2586d3Y7RtWtX0/bOnTtLlFNe+cXr0qWLWzHy5piUlKSjR4/me2x2drb27NlTovlatGihyMhI0z6rPy8AAAAAAAAAAAAAAAQK25tBcps+inrd3Q877Nq1y7TduHFjt2PkHZM3ZknljRcVFaWqVau6FSO/8yoozwMHDigjI6PI8YVxOBxq2LBhseYDAAAAAAAAAAAAAKCss+0xMfXr17etacNb8t4Bo379+m7HqFevnmn72LFjSklJUURERIlyy2VFjlWqVFFERIRSUlKc+3bv3q1rr722yPk8nbNevXqmx9vs3r3b7RgAAAAAAAAAAAAAAJQFtjWDxMXF2TW115w7d860HRMT43aMWrVq5RvXqmaQs2fPmrY9yVH6M899+/Y5t/Oee0HzhYaGun0nktz5LlXQfFb6y1/+ovDwcEti3XLLLXrkkUcKPWbKlCn68ssvLZkv1++//17o66dOndINN9xg6ZwPP/ywbr311kKPefrpp7Vk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+v3zn/+0MGN4E7Xn36i9wEVt2ovaClzUVulhzYlLUXv+jdoLXNSmvaitwGVVbaWlpWnJkiX69NNP9frrr+vVV1/VRx99pFWrVikzM9PirP0Ta05citrzb9Re4KI27VWma8sA4DMee+wxQ5IhyYiKijJOnz7t1vgzZ84YixYtMiZOnGgMHjzYiImJccbL/fjkk0+8k7wfyMzMND788EOjZcuWLp+XSz9atGhhTJ061cjKynJ7jilTpjjjhIWFGXv27PHCmcBq1J535eTkGHv27DFmzpxpPPLII8aVV15plCtXzuVzVBLUXmCiNs0++eSTQv//5cnHc889V+ic1FZg8qS2GjRoUOLvN3+qt5JgzYmCUHvexZoTnqI2zVhzwiol/Xlu/fr1xg033JDvtTz3IzIy0hg7dqxx7NgxL52F72LNiYJQe97FmhOeojbNWHOWHppBAB+xc+dOIzQ01HkhevHFF4s1btasWcatt95qxMbG+vUvG7xt586dRvPmzd36H0eHDh2MgwcPujVPenq66ZdC119/vXdOCJah9rwjKSnJeOqpp4y+ffsalStXLtbnqCSovcBDbbryxg9JEydOLHROaivweFpbgfxHLyux5kRBqD3vYM2JkqI2XbHmhBU8rS3D+PP74d577zUcDkexv8cqVqxofPHFF148I9/CmhMFofa8gzUnSoradMWas/TQDAL4iJtuusl5AYqMjDTOnz9frHE9e/YMiF82eNOKFSsKXKQFBQUZVapUMYKDg/N9vXbt2sbevXvdmu/tt982xVixYoWXzgxWoPa84+DBg24v1kqK2gss1KYrb/yQtG7duiLnpbYCi6e1Fch/9LIKa04UhtrzDtacKClq0xVrTljB09pKSUkp9Ge6SpUqGRUqVCjw9XfffdfLZ2Y/1pwoDLXnHaw5UVLUpivWnKXHYRiGIQC22rRpkzp06KDccnziiSf02muvFWtsr169tHz58mLP9cknn2jkyJGepOmXjh8/rvbt2+vkyZOm/cOGDdPDDz+sq666SiEhIcrJydHGjRs1bdo0TZ8+XTk5Oc5jW7RoobVr1yoiIqJYc6ampqpBgwY6ffq0pD+/RkuXLrXupGAZas974uLi1KhRI7fGlHRJQu0FDmozf7t37y7R9/Q///lPnT9/3rndsmVLbdu2rchx1FbgKEltNWzYUIcOHXJuv/jii6pWrZpb8/fu3VuXX365W2P8BWtOFIba8x7WnCgJajN/rDlRUiWprTvuuEMzZ8407WvcuLGeffZZ/eUvf1HVqlUlSSdOnNA333yjF1980bT+CgoK0k8//aRrrrnGorPxLaw5URhqz3tYc6IkqM38seYsRXZ0oAAwu/HGG51daMHBwcbhw4eLPfbSrsCgoCCjefPmxp133mn8+9//NlavXu3SGeer7zzxlkGDBpnO3+FwGNOmTSt0zI8//ujy3LUJEya4Ne9TTz1lGv/rr7+W5DTgJdSe9+TtmI+IiDC6d+9uPPbYY8Z//vMfY+LEiZZ3zBsGtRcoqE3rbdy40eXc//WvfxV7PLUVGEpSW3nfAe3uLaYDHWtOFIba8x7WnCgJatN6rDlhGJ7X1pw5c1y+f6677jojJSWlwDGnT5822rdvbxrTtGlTIzMz06rT8SmsOVEYas97WHOiJKhN67HmdA/NIIDNDhw4YAQFBTkvOoMGDXJr/Isvvmi89tprxtKlS43ExESX18vqH70MwzA2bNjgcv5PPPFEscZ+8MEHpnGVKlUyTp06Vey59+/fb3qG27Bhwzw9DXgJteddJ0+eNMaMGWNMnz7d2Lp1q5GVlWV6Pb/bwFmB2vN/1KZ3PPzww6bzDgkJMeLj44s9ntryfyWtLf7oVTDWnCgMteddrDnhKWrTO1hzoiS11aZNG9P3T+PGjY3k5OQix504ccKoUqWKaez7779fktPwSaw5URhqz7tYc8JT1KZ3sOZ0D80ggM3GjRtnumjNmzfP0vhl9Y9ehmEY9913n+ncq1ataqSmphZ7fMuWLU3jn3nmGbfm79Onj3NsUFAQvxzyMdSevbz1Q5JhUHv+jtq0XkZGhlG9enXTeQ8ePNjtONSWfytpbfFHr4Kx5kRhqD17seZEQahN67HmhGF4Xlu///67y/V69uzZxZ73jTfeMI2tV6+ekZOT4+FZ+CbWnCgMtWcv1pwoCLVpPdac7gsSANtkZWXp888/d25XqlRJAwYMsDGjwLJkyRLT9q233qry5csXe/w999xj2v7666/dmn/48OHOf+fk5GjGjBlujYf3UHuBjdrzX9SmdyxYsMD5HMxcI0eOdDsOteW/qC3vYs2JglB7gY3a81/Upnew5kRJaivveqpy5coaOnRosee+++67FRT0vz91HDlyRGvXri32eH/AmhMFofYCG7Xnv6hN72DN6T6aQQAbLVq0yHTRGjRokMLDw23MKHCcO3dOe/fuNe3r3r27WzGuvvpq0/auXbu0c+fOYo8fOnSo6X+4M2fOdGt+eA+1F9ioPf9FbXrHp59+atquXr26Bg8e7HYcast/UVvew5oThaH2Ahu157+oTe9gzYmS1NaaNWtM2127dlVoaGix565WrZqaNWtm2jd37txij/d1rDlRGGovsFF7/ova9A7WnO6jGQSw0VdffWXa7t+/v02ZBJ6TJ0+67GvSpIlbMZo2beqy77///W+xx9esWVPt27d3bu/du1cbN250Kwd4B7UX2Kg9/0VtWi8hIUELFy407fvrX//q1g+Quagt/0VteQ9rThSG2gts1J7/ojatx5oTUslqK++ayt31lOS6pnJnPeXrWHOiMNReYKP2/Be1aT3WnJ6hGQSwiWEYWrx4sWlfr1697EkmAJ09e9ZlX1RUlFsxIiMjXfZt377drRh5v6Z5/0eF0kftlQ3Unv+hNr1j5syZyszMNO3z5NaJuagt/0NteRdrThSE2isbqD3/Q216B2tOlLS28q6p3F1P5Tdm165dysnJcTuOL2LNiYJQe2UDted/qE3vYM3pGZpBAJts3rxZp06dcm7Xr19fDRo0sDGjwJLf7bbS09PdipHf8e7cPlGSevToYdpetGiRW+NhPWqvbKD2/A+16R2fffaZabtNmzZq166dx/GoLf/jzdqKi4vTwoULNWPGDH3++ef68ccftWHDBpcfzAMZa04UhNorG6g9/0NtegdrTpS0tvKuqdxdT0lSWlqaaTs1NVWHDh1yO44vYs2JglB7ZQO153+oTe9gzemZELsTAMqq1atXm7bbtGljUyaBqWrVqi77EhIS3IqR3/G7d+92K0ber+v69euVlZWlkBAuv3ah9soGas//UJvW27Rpk7Zs2WLaV5JueYna8kfeqq2OHTvqzJkz+b5Wvnx5XXnllRo1apRGjBgR0N8frDlREGqvbKD2/A+1aT3WnJBKXlt511TurqcKGrN79241atTI7Vi+hjUnCkLtlQ3Unv+hNq3HmtNz3BkEsMn69etN261atbIpk8BUq1YthYWFmfZt2LDBrRj5PR8sv9syFqZ+/fqqXLmyczstLU3btm1zKwasRe2VDdSe/6E2rffpp5+atkNDQ3XbbbeVKCa15X+8VVsF/cFL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as//UJslw5oTBbHr57msrCyNHDlSx44dc+675pprdNtttxVrvK/Uljex5gxs1F7ZQO35H2qzZFhzWotmEMAmDofD5cKybNkye5IJYPHx8VqyZEmxj//ll1/Uu3dvnTx50rmvb9++uuOOOzyaP+//TAYOHOhRHFiH2isbqD3/Q216btOmTS6d7HfffbdX5qK2/E9Ja+vXX3/VwIED9dtvv7k175QpU3TnnXea/mjmcDj0+uuvuxXHX7DmRF7UXtlA7fkfatNzrDlRGKt+nvvuu++UlJRUrGPj4+M1bNgwffPNN8595cuX19SpU92e11+w5kRe1F7ZQO35H2rTc6w5rRd49zoB/MiIESP0ySefOLd//PFHjRo1yq0YSUlJmjVrVrGPX7p0qdLS0vJ9rWPHji7PMvN38fHxuuaaa9S0aVMNGTJE1157rdq2bavo6GhJf76rJyEhQb/88ov+85//6PvvvzeNj42Ndevze6mTJ09q06ZNzu0mTZqoXbt2np8MLEPtlY7169dr/fr1+b72+++/u+wrbGF62223qVKlSsWal9rzX9SmZz799FPTdnh4uG699VbL56G2/FdJasswDC1cuFALFy5U48aNddNNN+mqq65S27ZtVbduXQUFBTmP27t3r5YsWaJ3331Xf/zxh0us5557Tp06dbLmpHwMa07kh9orHaw54S5q0zOsOVEUK36eGz9+vA4cOKBBgwZp0KBB6tSpk5o2beqsrdTUVG3cuFHz58/XtGnTlJiY6BwbFBSkGTNmqEmTJtackA9izYn8UHulgzUn3EVteoY1pxcYAGyTlZVlxMTEGJIMSUaFChWM1NRUt2IcPHjQOb6kH88995xH8z3//PMefga8b9OmTfmea1hYmFGtWjUjJCSkwM9H8+bNjcOHD3s89/vvv+83n6eyhtorHc8995xln6ODBw8We15qz39Rm+7LyMgwqlevbpr/5ptv9spc1Jb/KkltLV26tMAacTgcRqVKlYyqVasaQUFBhdbTo48+6lbOdteWu1hzIj/UXulgzQl3UZvuY82J4rDi57k2bdq4fK8HBQUZlStXNiIiIgqsqdDQUOOLL75wO2e7a8tdrDmRH2qvdLDmhLuoTfex5vQOHhMD2Cg4ONh0W77U1FT98MMPNmZUtB07dpi2HQ6Hhg0bZlM2nsvIyNCZM2eUlZXl8prD4dA999yjtWvXql69eh7PMWfOHOe/g4KCdOedd3ocC9ai9gIbtee/qE33LViwQKdPnzbtGzlypFfmorb8l7dqyzAMJSUl6ezZs8rJycn3mBo1amju3Ll688033Yptd21ZhTVn2UbtBTZqz39Rm+5jzYni8FZt5eTk6Pz580pJScn39SuuuEK///67R+8atru2rMKas2yj9gIbtee/qE33seb0DppBAJs9+OCDCg4Odm5Pnz7dxmyKlve5ZjfddJNatmxpTzLF0KhRI40fP16dOnVSSEjhT8aqWLGibr/9dm3YsEHTp09XxYoVPZ73wIEDWrp0qXP7hhtuUMOGDT2OB+tRe4GJ2vN/1KZ7PvvsM9N27dq11bdvX8vnobb8n6e11bZtW7333nsaMWJEsX95HBoaqiuvvFIfffSRDh06pKFDh7qdr9215S7WnCgItReYqD3/R226hzUniqukP8899dRTGjJkiCpXrlzocQ6HQ127dtWnn36qLVu2qEOHDp6ka3ttuYs1JwpC7QUmas//UZvuYc3pHQ7DMAy7kwDKultuuUWzZ8+W9GcH2oEDB9SgQQObs8pf586dtW7dOkl//g9m27ZtuuKKK2zOqnhSU1O1detW7du3T6dOnVJKSorCwsIUHR2t5s2bq0OHDgoNDbVkrqefflovv/yyc/vXX39V9+7dLYkN61B7gYfaCwzUpu+htgKDFbV19uxZ7dq1S0eOHNHJkyeVkpKinJwcRUZGqkqVKmrUqJE6dOigcuXKlShXf64t1pzIi9oLPNReYKA2fQ+1FRisqC3DMLRnzx5nfSUmJkqSIiMjFRsbq44dO6pGjRolztWfa4s1J/Ki9gIPtRcYqE3fU+Zqy74n1ADItWXLFsPhcDifTfX444/bnVK+EhMTjeDgYGeeI0aMsDsln5SammrUqFHD+Xnq0aOH3SmhANReYKH2Age16VuorcBBbQUWatN/UHuBhdoLHNSmb6G2Age1FVioTf9B7QUWai9wUJu+pSzWFo+JAXxA69atNXz4cOf2Bx98oPPnz9uXUAFWrFih7OxsSX92MI4fP97mjHzT9OnTlZCQ4Nx+6aWXbMwGhaH2Agu1FzioTd9CbQUOaiuwUJv+g9oLLNRe4KA2fQu1FTiorcBCbfoPai+wUHuBg9r0LWWxtmgGAXzExIkTnbfuS0pK0jvvvGNzRq4ufV7Y8OHDA/L2UCWVkZGhSZMmObcHDhyoq6++2saMUBRqLzBQe4GH2vQN1FbgobYCA7Xpf6i9wEDtBR5q0zdQW4GH2goM1Kb/ofYCA7UXeKhN31Bma8vuW5MA+J+///3vzlsTRUVFGadPn7Y7JZMuXboYkoygoCBj+/btdqfjk6ZMmeL8GoaFhRl79uyxOyUUA7Xn/6i9wERt2o/aCkzUlv+jNv0Ttef/qL3ARG3aj9oKTNSW/6M2/RO15/+ovcBEbdqvrNaWwzAMwytdJgDclpSUpMsvv1wnTpyQJI0bN06TJ0+2OSsUV1JSkmJjY523mPrHP/6hV155xeasUBzUnn+j9gIXtWkvaitwUVv+jdr0X9Sef6P2Ahe1aS9qK3BRW/6N2vRf1J5/o/YCF7Vpr7JcWzSDAAAAAAAAAAAAAAAABJAguxMAAAAAAAAAAAAAAACAdWgGAQAAAAAAAAAAAAAACCA0gwAAAAAAAAAAAAAAAAQQmkEAAAAAAAAAAAAAAAACCM0gAAAAAAAAAAAAAAAAAYRmEAAAAAAAAAAAAAAAgABCMwgAAAAAAAAAAAAAAEAAoRkEAAAAAAAAAAAAAAAggNAMAgAAAAAAAAAAAAAAEEBoBgEAAAAAAAAAAAAAAAggNIMAAAAAAAAAAAAAAAAEEJpBAAAAAAAAAAAAAAAAAgjNIAAAAAAAAAAAAAAAAAGEZhAAAAAAQIl8+umncjgcpo+4uDivjYM1+PwDADz14Ycfmv7/8eSTT9qdEjz0ww8/mL6Wt99+u90pAQAAwCI0gwAAAAAAAAAAiuXs2bP65z//6dyuVq2annrqKRszQkkMGjRIPXr0cG7PmjVLK1assDEjAAAAWIVmEAAAAAClKi4uzuVuBL169bIk9rJly1xijxw50pLYAFAS+V37CvsoX768YmJidPnll2vw4MGaMGGCfvnlF+Xk5Nh9KgDKuKeeekpnzpxxbj/zzDOKiooqclzDhg29dkeq/K6jvubHH390ybFp06Zem+/99993me+6667L99jXX3/dtP3ggw8qOzvba7kBAACgdNAMAgAAAADwKxMmTPD5P/gAJZWWlqaTJ09qz549WrBggZ5//nlde+21io2N1aRJk5SVlWV3ikCh8muA+vTTT+1OCyW0c+dOffTRR87tmjVrasyYMTZm5D/69eunOnXqmPbt27dPv/76q1fm+/jjj132jRo1Kt9ju3Tpon79+jm3t2zZos8//9wreQEAAKD00AwCAAAAAADgJ+Li4vT444+ra9eu2rt3r93pAChjnn32WdMdI8aNG6dy5crZmJH/CA4OzveOdZ988onlc/3xxx9av369aV/VqlU1ZMiQAsdc+ugfSXr++eeVkZFheW4AAAAoPTSDAAAAAAAA2CAiIkJt2rTJ96Np06aqUqVKgWM3bNiga6+9VkePHi3FjAGUZRs3btTcuXOd25GRkXrggQdszMj/3HPPPS53NJszZ46Sk5MtnSe/u4LcfvvtCg8PL3BMz5491aVLF+d2XFyc6S4wAAAA8D80gwAAAAAASmTkyJEyDMP00bBhQ7vTQhH4utmvY8eO2rx5c74fe/bs0dmzZ7Vv3z69+OKLql69usv4w4cPa/jw4TZkDqAseu2112QYhnP7jjvuUKVKlWzMyP80btxYvXr1Mu1LSUnRV199ZdkcmZmZmjlzpsv+e+65p8ix999/v2l70qRJysnJsSw3AAAAlC6aQQAAAAAAAHxUbGysnn76aW3btk2dO3d2eX316tWaM2eODZkBKEsOHTqkb775xrTvvvvusykb/zZq1CiXffndycNTCxYsUEJCgmlfhw4d1KZNmyLHjhgxQlFRUc7tAwcOaN68eZblBgAAgNJFMwgAAAAAAICPi4mJ0YIFCxQTE+Py2gcffGBDRgDKknfeeUfZ2dnO7U6dOqlVq1Y2ZuS/brzxRlWuXNm0b+XKldq7d68l8fNrLMmvASU/5cuX16233mraN2XKFEvyAgAAQOmjGQQAAAAAAMAP1KhRQ0888YTL/hUrVig1NdWGjACUBVlZWfr8889N+3hElefKlSunv/71ry77rbg7SHx8vBYtWmTaV758+XznK0jer+1vv/2m/fv3lzg3AAAAlL4QuxMAAAAAAF+VnJysXbt2ac+ePTpz5oySkpIUHh6uKlWqKDo6Wh07dsz3XfrekJqaqjVr1mj37t06d+6cQkJCFBMTo86dO+vyyy8vdpwzZ85o7dq12rdvn5KSkhQZGalatWqpZ8+eql69uhfPwD+dOnVK69ev16lTp3Tq1CkFBwcrOjpaNWvWVNeuXRUZGen1HHJycrRx40Zt27ZNp06dksPhUPXq1dW4cWN169ZNYWFhXs+hKNnZ2Tpw4IB27dqlY8eOKTExUdnZ2apSpYqqVKmiZs2aqVWrVgoKKp33pOzdu1cbNmzQsWPHlJ6ermrVqql27dq6+uqrVaVKlVLJwVuGDRumxx57zLQvPT1d27dvV6dOnQod64tfpy1btujo0aNKTk5WWFiYYmJidOeddxZr/LFjx7Rr1y7FxcXpwoULunjxoiIjI1W1alXVr19fnTp1Urly5bx8Fn86fPiw1q9fr0OHDiklJUWVKlVSkyZN1K1bN7e+53bu3KlNmzbpxIkTysjIUHR0tGJjY3X11VcrJMT6X+MZhqFt27Zp//79SkhI0JkzZxQREaEaNWqoYcOG6tSpk1fm9Ybz589r3bp1OnnypBISEpSenq7q1asrOjpanTp1Uq1atbyeQ+7/Mw4ePKgLFy44r9dDhw4t8v+xFy9e1Pbt27Vz506dO3dOSUlJCg4OVoUKFVSlShU1aNBAsbGxqlOnjtfPI6/Fixfr5MmTpn033XRTqecRSEaNGqX33nvPtG/GjBl68cUXFRwc7HHcGTNmKCsry7Rv2LBhpke/FKVnz56qUaOG6VEzM2bM0PPPP+9xXgAAALCJAQAAAACl6ODBg4Yk00fPnj0tib106VKX2HfddVexx2dmZhqLFy82Hn74YaN169aGw+FwiZf3IzY21nj22WeNhIQEj3L+5JNPXGIePHjQ+fquXbuM22+/3ShXrlyBObRv39744YcfCp3n119/Nfr3728EBwfnGyM4ONjo16+f8ccff1h+DlaM69mzZ5Ffi6I+Pvnkk2KdT2pqqvH6668bHTp0KPR7ICQkxOjevbsxffp0Iysrq/ifsP8vv+/XpUuXOl+/cOGCMX78eKNmzZoF5hAREWGMHDnSOHz4sNvze/p1y7V7927jlVdeMa677jojIiKiyM9/VFSUcdNNNxmrV692O9dceWM+99xzzteys7ONjz/+2GjZsmWBOQQHBxvXXHON8fvvv3ucg6esvPbl9/ku6Brga1+n5ORk45VXXjEaN25cYA4FSUhIMKZNm2aMGDGi0LrI/QgLCzN69OhhfPXVV0Z2drZH55L32pP3azZ79myjY8eOBeYQHh5u3HHHHcaRI0cKnCMtLc2YMmWK0aRJkwLjVK5c2fjnP/9ppKSkeHQeea1bt8644447ivw8VqpUyRg2bJixZs2aYsXN77ri7oc7dZGammpMmjTJuPLKKwv8/1vuxxVXXGG8+uqrRnJystufr8K+D3JycoxZs2YZXbt2LfD/GZde2/OaO3eucf311xuhoaHF+vzUrl3bGD58uDFz5kzjwoULbp+LJ26//XZTDi1atPAoToMGDUr0/53CuHMt8RVt27Yt9rW8uJo1a+YSc8mSJW7HufPOO00xmjRpUqK8AAAAYA/fXxUDAAAACCi+2gwye/Zso3r16h7/8apChQrGO++843bOhf1B/t133zXCw8OLncMjjzxi5OTkmOKnp6cb999/f7FjhISEGDNmzLDsHKwaV1rNIF9++aVRp04dt2NfccUVxvLly936vBXWDPLrr7+6lUf58uWN+fPnuzW/p1+306dPG+3atSvR1+KGG24wzp0751a+hlFwk8HRo0eNK6+80q0cnnrqKbfnLwkrr321a9d2iTVr1izTMb74dVq9erVRv379IufNz6233mqEhIR4fC7Nmzf3qNmtoCaACxcuGIMGDSr2/FFRUcYvv/ziEn/Hjh2FNjDl/WjSpIlHzV+54uLijGHDhnn0ORw2bFiR3w+l2Qzy4YcfGrVq1XI7fs2aNY05c+a49Xkr6PsgPj7e6NGjR5Fz5tcMcujQoWKNLezjySefdOs8PJGdne2yPnrggQc8ikUziNm///1vl5xvuukmj+OtXLnSJV7jxo1d1obFkV8t79692+PcAAAAYI/Sue8nAAAAAPi4HTt26PTp0x6PT01N1YMPPqj777/fknxefvlljR07Vunp6cUeM2XKFD399NPO7YyMDA0ZMkTvv/9+sWNkZWVp5MiRmj9/vlv5BoKJEyfqlltu0bFjx9weu337dvXt21f/+c9/SpzHggULdO2117qVx8WLF3XjjTdq0aJFJZ6/KElJSdq0aVOJYsyfP1+dO3fW0aNHS5zPgQMH1KVLF/3+++9ujXv55Zf1zDPPlHh+O1y4cMFlX+XKlU3bvvZ1+vXXX9WrVy8dPnzYo/GrVq1yefSBO3bu3KmuXbvqv//9r8cxciUlJal379764Ycfij3mwoULGjx4sDZv3uzct3nzZnXv3l1//PFHsePs27dPvXr1yvd7oCirV69W586dNXfuXLfHStLcuXPVtWtX7du3z6PxVsnMzNTf/vY3jR49WidOnHB7/MmTJzVixAhNnDixRHnEx8erW7du+vXXX90eGxcXp6uvvtqjsaVt3bp1LuujXr162ZNMgLnttttcHmX13Xff6cyZMx7F++STT1z23XPPPXI4HG7H6t27t8u+hQsXepQXAAAA7OMfD/0EAAAAgFLWoEEDtWvXTi1atFDdunVVqVIllS9fXsnJyTp+/Lg2b96sxYsXu/xBburUqWrVqpUeeOABj+f+9ttvTU0dNWvW1PXXX6/27durevXqSkpK0pYtW/TVV1/p5MmTprGvvvqqhgwZos6dO2vs2LGmX9w3a9ZM119/vZo2barKlSvr7NmzWrFihb7++mtT00lOTo7uv/9+9erVy61nzHtTkyZNdP78eUl//gEu73m3adOmyBhVq1Yt8LWJEydq/PjxLvtDQkLUu3dvXXvttapTp46ysrJ05MgR/fjjj1q9erUMw3Aem5GRodtuu03BwcEaMWJEMc/MbPPmzfrnP/+pjIwMSVL58uV1zTXXqEePHoqJiVFISIiOHDmin376Sb/88otpbFZWlv72t79p+/btpfp1q1ixojp16qTmzZuradOmioqKUqVKlZSRkaFz585px44dWrp0qXbu3Gkat3fvXt18881avny5QkI8+/VEUlKSBgwY4GyccTgc6tatm6699lrVr19fFStWVEJCglauXKl58+YpLS3NNP7VV1/V4MGD1aVLF89O3gaHDh1SSkqKy/4aNWoUOs7Or1N8fLyGDRtm+vx37txZ1113nRo0aKBKlSrpxIkT2rFjh+bMmVNkvODgYLVv315XXHGFmjVrpmrVqikyMlKGYSgxMVF79+7V6tWrtXLlSuXk5DjHJScn65ZbbtGmTZtUr149j85Fku68805t3LjRud2hQwcNGDBAjRo1UsWKFRUfH68lS5bo+++/N82fmpqqu+66Sxs3btTp06d1/fXXO//oGxoaqt69e6tPnz6qXbu2QkJCFBcXp/nz52vNmjWm+Q8cOKB//vOfeu+994qd87JlyzRgwACXGggKClL37t3VrVs3NWrUSJUrV9bFixd19OhRLV++XL/88ouys7Odx+/evVsDBw7U+vXrFRkZ6TJP1apVndfjjIwMl++nevXqFXotlv683hckJydHQ4YM0Y8//ujyWu3atXXNNdeoXbt2ql69usqVK6ezZ89q06ZNWrhwoakRyTAMjR8/XtWrV/eoiTMnJ0cjRozQgQMHnPsaN26sQYMGqVmzZqpevbrOnDmjgwcP6ptvvnEZf8899+jIkSMu+9u2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pdatW1vOWRgMHjzYFJszZ46OHz+uH3/80RCvWLGiunbt6tH+L126pAMHDhhijmYbAgAAQOFGMQgAAACA21pISIgplvM/2XOTlZWlwYMHW/62M1wXGBhoiv3++++Wcj3//POm2MiRI3XhwgWncyQlJWny5MmGmM1m0wsvvGBpTIWVv7+/SpcubYi5cq1I0qxZs7R27VoPjgo5FbfjlPMevWnTJmVkZDjdfs+ePZo0aZKnh1VkjBkzxhQbOXKk5XumK/z8/Eyzg1jtt2XLlqbClt9//12vvPKK1eEVWX/99Zdhu3z58nnaX/v27VWihPG/kHPOhOUsHx8fDRs2zBR/9dVXLf8d9fLLL5tijz76qCpVqmQpX2ExYMAA0/Xz2Wefac6cOab36qmnnnI4E487Nm/ebCq2evDBBz3aBwAAAPIexSAAAAAAbmutWrUyxSZMmODUFOhZWVl6+umntW7durwYGm6ifv36plhMTIylXF26dDF9y/rw4cPq27evU984T0tL00MPPWQqHunevbvuvfdeS2MqzCIiIgzba9eudfq9X7Fihf7v//4vL4aFHIrTccp5jz5//rzeeustp9oePnxYPXr00OXLl/NiaEVCmzZtTEuspKWlqVOnTtq3b5+lnJcuXdInn3xyy9ljSpQoobp16xpiK1euVFZWlqV+J0yYIJvNZohNnz5d48aNs7zMyO7duzVgwAClpaVZam/FK6+8or1791pqGxcXZyrEaNiwoSeGdVPlypUzzQjhzkwew4cPNy01EhcXp2effdblc+Ptt9/WsmXLTPGRI0e6lKdt27ay2WyGn7lz57qUw9OCg4NNs30cP35cEydONL3W0Swi7sp5jH19fdWuXTuP9wMAAIC8RTEIAAAAgNtaSEiI6cHpoUOH9OCDDyopKemm7RISEtSpUyfNmjVLklSyZEnTt/GRN+677z7TNPOTJk3S3LlzdfHiRZdy2Ww2zZ49W15eXob40qVL1bFjRx06dOimbbdu3aqIiAjt3LnTEA8ICNAHH3zg0jiKiscff9wU6927t5YsWXLTNhcvXtTbb7+thx56KPv45Dx+8KzidJweffRR06wE7777rt54441cC7a+/PJLPfDAA9kzURSGfSkoc+fONc2ScPDgQd1///2aNGmSU8uM2O12bdq0SSNGjFD16tX1zDPPODXLR4sWLQzbCQkJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(11, 7), dpi=200)\n", + "\n", + "plt.errorbar(\n", + " plot_labels,\n", + " physical_energy_diff,\n", + " yerr=physical_uncertainties.values(),\n", + " ecolor=(20 / 255.0, 26 / 255.0, 94 / 255.0),\n", + " color=(20 / 255.0, 26 / 255.0, 94 / 255.0),\n", + " capsize=4,\n", + " elinewidth=1.5,\n", + " fmt=\"o\",\n", + " markersize=8,\n", + " markeredgewidth=1,\n", + " label=\"Physical\",\n", + ")\n", + "plt.errorbar(\n", + " plot_labels,\n", + " logical_energy_diff,\n", + " yerr=logical_uncertainties.values(),\n", + " color=(0, 177 / 255.0, 152 / 255.0),\n", + " ecolor=(0, 177 / 255.0, 152 / 255.0),\n", + " capsize=4,\n", + " elinewidth=1.5,\n", + " fmt=\"o\",\n", + " markersize=8,\n", + " markeredgewidth=1,\n", + " label=\"Logical\",\n", + ")\n", + "\n", + "ax.set_xlabel(\"Hamiltonian Parameters (U, V)\", fontsize=18)\n", + "ax.set_ylabel(\"Energy above true ground state (in eV)\", fontsize=18)\n", + "ax.set_title(\"CUDA-Q AIM Infleqtion Hardware Execution (lower is better)\", fontsize=20)\n", + "ax.legend(loc=\"upper left\", fontsize=18.5)\n", + "plt.xticks(fontsize=16)\n", + "plt.yticks(fontsize=16)\n", + "\n", + "ax.axhline(y=0, color=\"black\", linestyle=\"--\", linewidth=2)\n", + "plt.ylim(top=max(physical_energy_diff) + max(physical_uncertainties.values()) + 0.2, bottom=-0.2)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/sphinx/targets/cpp/infleqtion.cpp b/docs/sphinx/targets/cpp/infleqtion.cpp new file mode 100644 index 0000000000..4a61b71571 --- /dev/null +++ b/docs/sphinx/targets/cpp/infleqtion.cpp @@ -0,0 +1,65 @@ +// Compile and run with: +// ``` +// nvq++ --target infleqtion infleqtion.cpp -o out.x && ./out.x +// ``` +// This will submit the job to the Infleqtion's ideal simulator, +// cq_sqale_simulator (default). Alternatively, we can enable hardware noise +// model simulation by specifying `noise-sim` to the flag `--infleqtion-method`, +// e.g., +// ``` +// nvq++ --target infleqtion --infleqtion-machine cq_sqale_qpu +// --infleqtion-method noise-sim infleqtion.cpp -o out.x && ./out.x +// ``` +// where "noise-sim" instructs Superstaq to perform a noisy emulation of the +// QPU. An ideal dry-run execution on the QPU may be performed by passing +// `dry-run` to the `--infleqtion-method` flag, e.g., +// ``` +// nvq++ --target infleqtion --infleqtion-machine cq_sqale_qpu +// --infleqtion-method dry-run infleqtion.cpp -o out.x && ./out.x +// ``` +// Note: If targeting ideal cloud simulation, `--infleqtion-machine +// cq_sqale_simulator` is optional since it is the default configuration if not +// provided. + +#include +#include + +// Define a simple quantum kernel to execute on Infleqtion backends. +struct ghz { + // Maximally entangled state between 5 qubits. + auto operator()() __qpu__ { + cudaq::qvector q(5); + h(q[0]); + for (int i = 0; i < 4; i++) { + x(q[i], q[i + 1]); + } + auto result = mz(q); + } +}; + +int main() { + // Submit to infleqtion asynchronously (e.g., continue executing + // code in the file until the job has been returned). + auto future = cudaq::sample_async(ghz{}); + // ... classical code to execute in the meantime ... + + // Can write the future to file: + { + std::ofstream out("saveMe.json"); + out << future; + } + + // Then come back and read it in later. + cudaq::async_result readIn; + std::ifstream in("saveMe.json"); + in >> readIn; + + // Get the results of the read in future. + auto async_counts = readIn.get(); + async_counts.dump(); + + // OR: Submit to infleqtion synchronously (e.g., wait for the job + // result to be returned before proceeding). + auto counts = cudaq::sample(ghz{}); + counts.dump(); +} diff --git a/docs/sphinx/targets/python/infleqtion.py b/docs/sphinx/targets/python/infleqtion.py new file mode 100644 index 0000000000..20cb330d1d --- /dev/null +++ b/docs/sphinx/targets/python/infleqtion.py @@ -0,0 +1,54 @@ +import cudaq + +# You only have to set the target once! No need to redefine it +# for every execution call on your kernel. +# To use different targets in the same file, you must update +# it via another call to `cudaq.set_target()` +cudaq.set_target("infleqtion") + + +# Create the kernel we'd like to execute on Infleqtion. +@cudaq.kernel +def kernel(): + qvector = cudaq.qvector(2) + h(qvector[0]) + x.ctrl(qvector[0], qvector[1]) + mz(qvector) + + +# Note: All measurements must be terminal when performing the sampling. + +# Execute on Infleqtion and print out the results. + +# Option A (recommended): +# By using the asynchronous `cudaq.sample_async`, the remaining +# classical code will be executed while the job is being handled +# by the Superstaq API. This is ideal when submitting via a queue +# over the cloud. +async_results = cudaq.sample_async(kernel) +# ... more classical code to run ... + +# We can either retrieve the results later in the program with +# ``` +# async_counts = async_results.get() +# ``` +# or we can also write the job reference (`async_results`) to +# a file and load it later or from a different process. +file = open("future.txt", "w") +file.write(str(async_results)) +file.close() + +# We can later read the file content and retrieve the job +# information and results. +same_file = open("future.txt", "r") +retrieved_async_results = cudaq.AsyncSampleResult(str(same_file.read())) + +counts = retrieved_async_results.get() +print(counts) + +# Option B: +# By using the synchronous `cudaq.sample`, the execution of +# any remaining classical code in the file will occur only +# after the job has been returned from Superstaq. +counts = cudaq.sample(kernel) +print(counts) diff --git a/docs/sphinx/using/applications.rst b/docs/sphinx/using/applications.rst index 572187128f..b3119decf4 100644 --- a/docs/sphinx/using/applications.rst +++ b/docs/sphinx/using/applications.rst @@ -22,7 +22,8 @@ Applications that give an in depth view of CUDA-Q and its applications in Python /applications/python/quantum_teleportation.ipynb /applications/python/quantum_volume.ipynb /applications/python/readout_error_mitigation.ipynb + /applications/python/vqe.ipynb /applications/python/vqe_advanced.ipynb /applications/python/hadamard_test.ipynb - /applications/python/vqe.ipynb - \ No newline at end of file + /applications/python/logical_aim_sqale.ipynb + diff --git a/docs/sphinx/using/backends/backends.rst b/docs/sphinx/using/backends/backends.rst index e5a8c9b087..9ee2bbbbbf 100644 --- a/docs/sphinx/using/backends/backends.rst +++ b/docs/sphinx/using/backends/backends.rst @@ -12,11 +12,12 @@ CUDA-Q Backends **The following is a comprehensive list of the available targets in CUDA-Q:** +* :ref:`anyon ` * :ref:`braket ` * :ref:`density-matrix-cpu ` * :ref:`fermioniq ` +* :ref:`infleqtion ` * :ref:`ionq ` -* :ref:`anyon ` * :ref:`iqm ` * :ref:`nvidia ` * :ref:`nvidia-fp64 ` @@ -35,6 +36,6 @@ CUDA-Q Backends * :ref:`tensornet-mps ` .. deprecated:: 0.8 - The `nvidia-fp64`, `nvidia-mgpu`, `nvidia-mqpu`, and `nvidia-mqpu-fp64` targets can be + The `nvidia-fp64`, `nvidia-mgpu`, `nvidia-mqpu`, and `nvidia-mqpu-fp64` targets can be enabled as extensions of the unified `nvidia` target (see `nvidia` :ref:`target documentation `). These target names might be removed in a future release. \ No newline at end of file diff --git a/docs/sphinx/using/backends/hardware.rst b/docs/sphinx/using/backends/hardware.rst index 366e837173..33f4907cec 100644 --- a/docs/sphinx/using/backends/hardware.rst +++ b/docs/sphinx/using/backends/hardware.rst @@ -112,6 +112,128 @@ To see a complete example for using Amazon Braket backends, take a look at our : The ``cudaq.observe`` API is not yet supported on the `braket` target. +Infleqtion +================================== + +.. _infleqtion-backend: + +Infleqtion is a quantum hardware provider of gate-based neutral atom quantum computers. Their backends may be +accessed via `Superstaq `__, Infleqtion’s cross-platform software API +that performs low-level compilation and cross-layer optimization. To get started users can create a Superstaq +account by following `these instructions `__. + +For access to Infleqtion's neutral atom quantum computer, Sqale, +`pre-registration `__ is now open. + +Setting Credentials +````````````````````````` + +Programmers of CUDA-Q may access Infleqtion backends from either C++ or Python. Generate +an API key from your `Superstaq account `__ and export +it as an environment variable: + +.. code:: bash + + export SUPERSTAQ_API_KEY="superstaq_api_key" + +Submission from C++ +````````````````````````` + +To target quantum kernel code for execution on Infleqtion's backends, +pass the flag ``--target infleqtion`` to the ``nvq++`` compiler. + +.. code:: bash + + nvq++ --target infleqtion src.cpp + +This will take the API key and handle all authentication with, and submission to, Infleqtion's QPU +(or simulator). By default, quantum kernel code will be submitted to Infleqtion's Sqale +simulator. + +To execute your kernels on a QPU, pass the ``--infleqtion-machine`` flag to the ``nvq++`` compiler +to specify which machine to submit quantum kernels to: + +.. code:: bash + + nvq++ --target infleqtion --infleqtion-machine cq_sqale_qpu src.cpp ... + +where ``cq_sqale_qpu`` is an example of a physical QPU. + +To run an ideal dry-run execution on the QPU, additionally pass ``dry-run`` with the ``--infleqtion-method`` +flag to the ``nvq++`` compiler: + +.. code:: bash + + nvq++ --target infleqtion --infleqtion-machine cq_sqale_qpu --infleqtion-method dry-run src.cpp ... + +To noisily simulate the QPU instead, pass ``noise-sim`` to the ``--infleqtion-method`` flag like so: + +.. code:: bash + + nvq++ --target infleqtion --infleqtion-machine cq_sqale_qpu --infleqtion-method noise-sim src.cpp ... + +Alternatively, to emulate the Infleqtion machine locally, without submitting through the cloud, +you can also pass the ``--emulate`` flag to ``nvq++``. This will emit any target +specific compiler diagnostics, before running a noise free emulation. + +.. code:: bash + + nvq++ --emulate --target infleqtion src.cpp + +To see a complete example for using Infleqtion's backends, take a look at our :doc:`C++ examples <../examples/examples>`. + +Submission from Python +````````````````````````` + +The target to which quantum kernels are submitted +can be controlled with the ``cudaq::set_target()`` function. + +.. code:: python + + cudaq.set_target("infleqtion") + +By default, quantum kernel code will be submitted to Infleqtion's Sqale +simulator. + +To specify which Infleqtion QPU to use, set the :code:`machine` parameter. + +.. code:: python + + cudaq.set_target("infleqtion", machine="cq_sqale_qpu") + +where ``cq_sqale_qpu`` is an example of a physical QPU. + +To run an ideal dry-run execution of the QPU, additionally set the ``method`` flag to ``"dry-run"``. + +.. code:: python + + cudaq.set_target("infleqtion", machine="cq_sqale_qpu", method="dry-run") + +To noisily simulate the QPU instead, set the ``method`` flag to ``"noise-sim"``. + +.. code:: python + + cudaq.set_target("infleqtion", machine="cq_sqale_qpu", method="noise-sim") + +Alternatively, to emulate the Infleqtion machine locally, without submitting through the cloud, +you can also set the ``emulate`` flag to ``True``. This will emit any target +specific compiler diagnostics, before running a noise free emulation. + +.. code:: python + + cudaq.set_target("infleqtion", emulate=True) + +The number of shots for a kernel execution can be set through +the ``shots_count`` argument to ``cudaq.sample`` or ``cudaq.observe``. By default, +the ``shots_count`` is set to 1000. + +.. code:: python + + cudaq.sample(kernel, shots_count=100) + +To see a complete example for using Infleqtion's backends, take a look at our :doc:`Python examples <../examples/examples>`. +Moreover, for an end-to-end application workflow example executed on the Infleqtion QPU, take a look at the +:doc:`Anderson Impurity Model ground state solver <../applications>` notebook. IonQ ================================== diff --git a/docs/sphinx/using/examples/hardware_providers.rst b/docs/sphinx/using/examples/hardware_providers.rst index 96fbc559f2..6abbb8dea7 100644 --- a/docs/sphinx/using/examples/hardware_providers.rst +++ b/docs/sphinx/using/examples/hardware_providers.rst @@ -2,7 +2,7 @@ Using Quantum Hardware Providers ----------------------------------- CUDA-Q contains support for using a set of hardware providers (Amazon Braket, -IonQ, IQM, OQC, ORCA Computing, Quantinuum and QuEra Computing). +Infleqtion, IonQ, IQM, OQC, ORCA Computing, Quantinuum, and QuEra Computing). For more information about executing quantum kernels on different hardware backends, please take a look at :doc:`hardware <../backends/hardware>`. @@ -21,6 +21,21 @@ The following code illustrates how to run kernels on Amazon Braket's backends. .. literalinclude:: ../../targets/cpp/braket.cpp :language: cpp +Infleqtion +================================== + +The following code illustrates how to run kernels on Infleqtion's backends. + +.. tab:: Python + + .. literalinclude:: ../../targets/python/infleqtion.py + :language: python + +.. tab:: C++ + + .. literalinclude:: ../../targets/cpp/infleqtion.cpp + :language: cpp + IonQ ================================== From a1f765c06e8b7e915a2349033795705e4ce49e27 Mon Sep 17 00:00:00 2001 From: Thien Nguyen <58006629+1tnguyen@users.noreply.github.com> Date: Thu, 12 Dec 2024 03:04:59 +1100 Subject: [PATCH 23/26] Fix a typo in the docs: mgpu -> mqpu (#2463) Signed-off-by: Thien Nguyen --- docs/sphinx/using/backends/platform.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/using/backends/platform.rst b/docs/sphinx/using/backends/platform.rst index ad395ebc55..da019f3f65 100644 --- a/docs/sphinx/using/backends/platform.rst +++ b/docs/sphinx/using/backends/platform.rst @@ -96,7 +96,7 @@ QPU via the :code:`cudaq::get_state_async` (C++) or :code:`cudaq.get_state_async ./a.out .. deprecated:: 0.8 - The :code:`nvidia-mqpu` and :code:`nvidia-mqpu-fp64` targets, which are equivalent to the multi-QPU options `mgpu,fp32` and `mgpu,fp64`, respectively, of the :code:`nvidia` target, are deprecated and will be removed in a future release. + The :code:`nvidia-mqpu` and :code:`nvidia-mqpu-fp64` targets, which are equivalent to the multi-QPU options `mqpu,fp32` and `mqpu,fp64`, respectively, of the :code:`nvidia` target, are deprecated and will be removed in a future release. Parallel distribution mode ^^^^^^^^^^^^^^^^^^^^^^^^^^ From ade221c3418190a3ef6111512e2836f17badf3de Mon Sep 17 00:00:00 2001 From: Luca Mondada <72734770+lmondada@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:07:03 +0000 Subject: [PATCH 24/26] Document C++ API for get_state, sample and observe (#2140) Signed-off-by: Bettina Heim Co-authored-by: Eric Schweitz Co-authored-by: Bettina Heim --- docs/sphinx/api/languages/cpp_api.rst | 17 +++++++++++++++++ runtime/cudaq/algorithms/observe.h | 19 +++++++++++++------ runtime/cudaq/algorithms/sample.h | 2 ++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/sphinx/api/languages/cpp_api.rst b/docs/sphinx/api/languages/cpp_api.rst index b16e570f53..34487dbefb 100644 --- a/docs/sphinx/api/languages/cpp_api.rst +++ b/docs/sphinx/api/languages/cpp_api.rst @@ -35,6 +35,14 @@ Common .. doxygenclass:: cudaq::observe_result :members: +.. doxygenstruct:: cudaq::observe_options + :members: + +.. doxygenfunction:: cudaq::observe(const observe_options &options, QuantumKernel &&kernel, spin_op H, Args &&...args) +.. doxygenfunction:: cudaq::observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, Args &&...args) +.. doxygenfunction:: cudaq::observe(QuantumKernel &&kernel, spin_op H, Args &&...args) +.. doxygenfunction:: cudaq::observe(QuantumKernel &&kernel, const SpinOpContainer &termList, Args &&...args) + .. doxygenclass:: cudaq::ExecutionContext :members: @@ -53,6 +61,13 @@ Common .. doxygenclass:: cudaq::sample_result :members: +.. doxygenstruct:: cudaq::sample_options + :members: + +.. doxygenfunction:: cudaq::sample(const sample_options &options, QuantumKernel &&kernel, Args &&...args) +.. doxygenfunction:: cudaq::sample(std::size_t shots, QuantumKernel &&kernel, Args &&...args) +.. doxygenfunction:: cudaq::sample(QuantumKernel &&kernel, Args&&... args) + .. doxygenclass:: cudaq::SimulationState .. doxygenstruct:: cudaq::SimulationState::Tensor @@ -89,6 +104,8 @@ Common .. doxygenfunction:: cudaq::draw(QuantumKernel &&kernel, Args&&... args) +.. doxygenfunction:: cudaq::get_state(QuantumKernel &&kernel, Args&&... args) + .. doxygenclass:: cudaq::Resources .. doxygentypedef:: cudaq::complex_matrix::value_type diff --git a/runtime/cudaq/algorithms/observe.h b/runtime/cudaq/algorithms/observe.h index 6e5abe392b..407a528013 100644 --- a/runtime/cudaq/algorithms/observe.h +++ b/runtime/cudaq/algorithms/observe.h @@ -54,13 +54,12 @@ concept ObserveCallValid = HasVoidReturnType>; #endif -/// Observe options to provide as an argument to the `observe()`, +/// @brief Observe options to provide as an argument to the `observe()`, /// `async_observe()` functions. -/// -/// \p shots is the number of shots to run for the given kernel. The default of -/// -1 means direct calculations for simulation backends. \p noise is the noise -/// model to use for the observe operation. -/// \p num_trajectories is the optional number of trajectories to be used when +/// @param shots number of shots to run for the given kernel, or -1 if not +/// applicable. +/// @param noise noise model to use for the sample operation +/// @param num_trajectories is the optional number of trajectories to be used when /// computing the expectation values in the presence of noise. This parameter is /// only applied to simulation backends that support noisy /// simulation of trajectories. @@ -216,6 +215,7 @@ inline auto distributeComputations( } // namespace details +/// \overload /// \brief Compute the expected value of `H` with respect to `kernel(Args...)`. #if CUDAQ_USE_STD20 template @@ -283,6 +283,9 @@ std::vector observe(QuantumKernel &&kernel, return results; } +// Doxygen: ignore overloads with `DistributionType`s, preferring the simpler +// ones +/// @cond /// @brief Compute the expected value of `H` with respect to `kernel(Args...)`. /// Distribute the work `amongst` available QPUs on the platform in parallel. /// This distribution can occur on multi-GPU multi-node platforms, multi-GPU @@ -404,7 +407,9 @@ observe_result observe(QuantumKernel &&kernel, spin_op H, Args &&...args) { return observe(shots, std::forward(kernel), H, std::forward(args)...); } +/// \endcond +/// \overload /// \brief Compute the expected value of `H` with respect to `kernel(Args...)`. /// Specify the number of shots. #if CUDAQ_USE_STD20 @@ -581,6 +586,7 @@ auto observe_async(QuantumKernel &&kernel, spin_op &H, Args &&...args) { std::forward(args)...); } +/// @overload /// @brief Run the standard observe functionality over a set of `N` /// argument packs. For a kernel with signature `void(Args...)`, this /// function takes as input a set of `vector...`, a vector for @@ -623,6 +629,7 @@ std::vector observe(QuantumKernel &&kernel, spin_op H, numQpus, platform, functor, params); } +/// @overload /// @brief Run the standard observe functionality over a set of N /// argument packs. For a kernel with signature `void(Args...)`, this /// function takes as input a set of `vector...`, a vector for diff --git a/runtime/cudaq/algorithms/sample.h b/runtime/cudaq/algorithms/sample.h index 41d8d10405..9d2de93f86 100644 --- a/runtime/cudaq/algorithms/sample.h +++ b/runtime/cudaq/algorithms/sample.h @@ -186,6 +186,7 @@ struct sample_options { cudaq::noise_model noise; }; +/// @overload /// @brief Sample the given quantum kernel expression and return the /// mapping of observed bit strings to corresponding number of /// times observed. @@ -226,6 +227,7 @@ sample_result sample(QuantumKernel &&kernel, Args &&...args) { .value(); } +/// @overload /// @brief Sample the given quantum kernel expression and return the /// mapping of observed bit strings to corresponding number of /// times observed. Specify the number of shots. From 8262655bba27b3d0cb56076352dad4ad5893985c Mon Sep 17 00:00:00 2001 From: Monica VanDieren <150082832+mmvandieren@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:08:46 -0800 Subject: [PATCH 25/26] copy edits. Plus fixed deprecated backend cudaq.set_target("nvidia-mqpu") (#2455) Signed-off-by: Monica VanDieren <150082832+mmvandieren@users.noreply.github.com> Signed-off-by: Eric Schweitz Co-authored-by: Eric Schweitz --- .../applications/python/hadamard_test.ipynb | 36 +++++++------- docs/sphinx/applications/python/krylov.ipynb | 48 +++++++++++-------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/docs/sphinx/applications/python/hadamard_test.ipynb b/docs/sphinx/applications/python/hadamard_test.ipynb index 8199b74d6b..a643f59ba3 100644 --- a/docs/sphinx/applications/python/hadamard_test.ipynb +++ b/docs/sphinx/applications/python/hadamard_test.ipynb @@ -6,14 +6,14 @@ "source": [ "# Using the Hadamard Test to Determine Quantum Krylov Subspace Decomposition Matrix Elements\n", "\n", - "The Hadamard test, is a quantum algorithm for estimating the expectation values and is a useful subroutine for a number of quantum applications ranging from estimation of molecular ground state energies to quantum semidefinite programming. This tutorial will briefly introduce the Hadamard test, and demonstrate how it can be implemented in CUDA-Q and then parallelized for a Quantum Krylov Subspace Diagonalization application.\n", + "The Hadamard test is a quantum algorithm for estimating expectation values and is a useful subroutine for a number of quantum applications ranging from estimation of molecular ground state energies to quantum semidefinite programming. This tutorial will briefly introduce the Hadamard test, demonstrate how it can be implemented in CUDA-Q, and then parallelized for a Quantum Krylov Subspace Diagonalization application.\n", "\n", "The Hadamard test is performed using a register with an ancilla qubit in the $\\ket{0}$ state and a prepared quantum state $\\ket{\\psi}$, the following circuit can be used to extract the expectation value from measurement of the ancilla.\n", "\n", "\n", "![Htest](./images/htest.png)\n", "\n", - "The key insight is to note that $$P(0) = \\frac{1}{2} \\left[ I + Re \\bra{\\psi} O \\ket{\\phi} \\right]$$ and $$P(1) = \\frac{1}{2} \\left[ I - Re \\bra{\\psi} O \\ket{\\phi} \\right]$$ so their difference is equal to $$P(0)-P(1) = Re \\bra{\\psi} O \\ket{\\phi}$$\n", + "The key insight is that $$P(0) = \\frac{1}{2} \\left[ I + Re \\bra{\\psi} O \\ket{\\phi} \\right]$$ and $$P(1) = \\frac{1}{2} \\left[ I - Re \\bra{\\psi} O \\ket{\\phi} \\right]$$ so their difference is equal to $$P(0)-P(1) = Re \\bra{\\psi} O \\ket{\\phi}.$$\n", "\n", "\n", "More details and a short derivation can be found [here](https://en.wikipedia.org/wiki/Hadamard_test)." @@ -26,18 +26,18 @@ "What if you want to perform the Hadamard test to compute an expectation value like $\\bra{\\psi} O \\ket{\\phi}$, where $\\ket{\\psi}$ and $\\ket{\\phi}$ are different states and $O$ is a Pauli Operator? This is a common subroutine for the QKSD, where matrix elements are determined by computing expectation values between different states.\n", "\n", "Defining $O$ as \n", - "$$O = X_1X_2$$\n", + "$$O = X_1X_2,$$\n", "\n", "and given the fact that\n", - "$$\\ket{\\psi} = U_{\\psi}\\ket{0} \\qquad \\ket{\\phi} = U_{\\phi}\\ket{0}$$\n", + "$$\\ket{\\psi} = U_{\\psi}\\ket{0} \\qquad \\ket{\\phi} = U_{\\phi}\\ket{0},$$\n", "\n", - "We can combine the state preparation steps into the operator resulting in\n", - "$$\\bra{\\psi}O\\ket{\\phi} = \\bra{0}U_\\psi^\\dagger O U_\\phi\\ket{0}$$\n", - "Which corresponds to the following circuit\n", + "we can combine the state preparation steps into the operator resulting in\n", + "$$\\bra{\\psi}O\\ket{\\phi} = \\bra{0}U_\\psi^\\dagger O U_\\phi\\ket{0},$$\n", + "which corresponds to the following circuit.\n", "![Htest2](./images/htestfactored.png)\n", "\n", - "By preparing this circuit, and repeatedly measuring the ancilla qubit, allows for estimation of the expectation value as $$P(0)-P(1) = Re \\bra{\\psi} O \\ket{\\phi}$$\n", - "\n", + "By preparing this circuit, and repeatedly measuring the ancilla qubit, we estimate the expectation value as $$P(0)-P(1) = Re \\bra{\\psi} O \\ket{\\phi}.$$\n", + "\, "\n", "The following sections demonstrate how this can be performed in CUDA-Q." ] @@ -53,7 +53,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Before performing the Hadamard test, lets determine the exact expectation value by performing the matrix multiplications explicitly. The code below builds two CUDA-Q kernels corresponding to $\\ket{\\psi} = \\frac{1}{\\sqrt{2}}\\begin{pmatrix}1 \\\\ 0 \\\\ 1 \\\\ 0\\end{pmatrix}$ and $\\ket{\\phi} = \\begin{pmatrix}0 \\\\ 1 \\\\ 0 \\\\ 0\\end{pmatrix}$" + "Before performing the Hadamard test, let's determine the exact expectation value by performing the matrix multiplications explicitly. The code below builds two CUDA-Q kernels corresponding to $\\ket{\\psi} = \\frac{1}{\\sqrt{2}}\\begin{pmatrix}1 \\\\ 0 \\\\ 1 \\\\ 0\\end{pmatrix}$ and $\\ket{\\phi} = \\begin{pmatrix}0 \\\\ 1 \\\\ 0 \\\\ 0\\end{pmatrix}.$" ] }, { @@ -87,7 +87,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The state vectors can be accessed using the `get_state` command and printed as numpy arrays" + "The state vectors can be accessed using the `get_state` command and printed as numpy arrays:" ] }, { @@ -118,7 +118,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The Hamiltonian operator ($O$ in the derivation above) is defined as a CUDA-Q spin operator and converted to a matrix withe the `to_matrix`. The following line of code performs the explicit matrix multiplications to produce the exact expectation value." + "The Hamiltonian operator ($O$ in the derivation above) is defined as a CUDA-Q spin operator and converted to a matrix with `to_matrix`. The following line of code performs the explicit matrix multiplications to produce the exact expectation value." ] }, { @@ -208,7 +208,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The CUDA-Q Sample method computes 100000 sample ancilla measurements and uses them to estimate the expectation value. The standard error is provided as well. Try increasing the sample size and note the convergence of the expectation value and the standard error towards the numerical result." + "The CUDA-Q `sample` method computes 100000 sample ancilla measurements, and from them we can estimate the expectation value. The standard error is provided as well. Try increasing the sample size and note the convergence of the expectation value and the standard error towards the numerical result." ] }, { @@ -249,9 +249,9 @@ "\n", "![Htest3](./images/QKSD.png)\n", "\n", - "This method can be easily parallelized and multiple QPUs, if available could compute the matrix elements asynchronously. The CUDA-Q `mqpu` backend allows you to simulate a computation across multiple simulated QPUs. The code below demonstrates how.\n", + "This method can be easily parallelized, and multiple QPUs, if available, could compute the matrix elements asynchronously. The CUDA-Q `mqpu` backend allows you to simulate a computation across multiple simulated QPUs. The code below demonstrates how.\n", "\n", - "First, the Hadamard test circuit is defined, but this time the $\\ket{\\psi}$ and $\\ket{\\phi}$ states contain parameterized rotations so that multiple states can be quickly generated for the sake of example." + "First, the Hadamard test circuit is defined, but this time the $\\ket{\\psi}$ and $\\ket{\\phi}$ states contain parameterized rotations so that multiple states can be quickly generated, for the sake of example." ] }, { @@ -302,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -314,7 +314,7 @@ } ], "source": [ - "cudaq.set_target(\"nvidia-mqpu\")\n", + "cudaq.set_target(\"nvidia\", option=\"mqpu\")\n", "\n", "target = cudaq.get_target()\n", "qpu_count = target.num_qpus()\n", @@ -354,7 +354,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The four matrix elements are shown below and now be classically processed to produce the eigenvalues." + "The four matrix elements are shown below and can be classically processed to produce the eigenvalues." ] }, { diff --git a/docs/sphinx/applications/python/krylov.ipynb b/docs/sphinx/applications/python/krylov.ipynb index 1954212c02..183a13d691 100644 --- a/docs/sphinx/applications/python/krylov.ipynb +++ b/docs/sphinx/applications/python/krylov.ipynb @@ -7,39 +7,45 @@ "source": [ "# Multi-reference Quantum Krylov Algorithm - $H_2$ Molecule\n", "\n", - "The multireference selected quantum Krylov (MRSQK) algorithm is defined in [this paper](https://arxiv.org/pdf/1911.05163) and was developed as a low-cost alternative to quantum phase estimation. This tutorial will demonstrate how this algorithm can be implemented in CUDA-Q and accelerated using multiple GPUs. The CUDA-Q Hadamard test tutorial might provide helpful background information for understanding this tutorial.\n", + "The multireference selected quantum Krylov (MRSQK) algorithm is defined in [this paper](https://arxiv.org/pdf/1911.05163) and was developed as a low-cost alternative to quantum phase estimation. This tutorial will demonstrate how this algorithm can be implemented in CUDA-Q and accelerated using multiple GPUs. The [CUDA-Q Hadamard test tutorial](https://nvidia.github.io/cuda-quantum/latest/applications/python/hadamard_test.html) might provide helpful background information for understanding this tutorial.\n", "\n", "The algorithm works by preparing an initial state, and then defining this state in a smaller subspace constructed with a basis that corresponds to Trotter steps of the initial state. This subspace can be diagonalized to produce an approximate energy for the system without variational optimization of any parameters.\n", "\n", "In the example below, the initial guess is the ground state of the diagonalized Hamiltonian for demonstration purposes. In practice one could use a number of heuristics to prepare the ground state such as Hartree Fock or CISD. A very promising ground state preparation method which can leverage quantum computers is the linear combination of unitaries (LCU). LCU would allow for the state preparation to occur completely on the quantum computer and avoid storing an inputting the exponentially large state vector.\n", "\n", "\n", - "Regardless of the method used for state preparation, the procedure begins by selecting a $d$ dimensional basis of reference states ${\\Phi_0 \\cdots \\Phi_d}$ where each is a linear combination of slater determinants. \n", + "Regardless of the method used for state preparation, the procedure begins by selecting a $d$-dimensional basis of reference states ${\\Phi_0 \\cdots \\Phi_d},$ where each is a linear combination of Slater determinants: \n", "\n", - "$$ \\ket{\\Phi_I} = \\sum_{\\mu} d_{\\mu I}\\ket{\\phi_{\\mu}} $$\n", + "$$ \\ket{\\Phi_I} = \\sum_{\\mu} d_{\\mu I}\\ket{\\phi_{\\mu}}. $$\n", "\n", "\n", - "From this, a non-orthogonal Krylov Space $\\mathcal{K} = \\{\\psi_{0} \\cdots \\psi_{N}\\}$ is constructed by applying a family of $s$ unitary operators on each of the $d$ reference states resulting in $d*s = N$ elements in the Krylov space where, \n", - "$$ \\ket{\\psi_{\\alpha}} \\equiv \\ket{\\psi_I^{(n)}} = \\hat{U}_n\\ket{\\Phi_I} $$\n", + "From this, a non-orthogonal Krylov Space $\\mathcal{K} = \\{\\psi_{0} \\cdots \\psi_{N}\\}$ is constructed by applying a family of $s$ unitary operators on each of the $d$ reference states resulting in $d*s = N$ elements in the Krylov space where \n", + "$$ \\ket{\\psi_{\\alpha}} \\equiv \\ket{\\psi_I^{(n)}} = \\hat{U}_n\\ket{\\Phi_I}, $$\n", "\n", "Therefore, the general quantum state that we originally set out to describe is\n", "\n", - "$$ \\ket{\\Psi} = \\sum_{\\alpha} c_{\\alpha}\\ket{\\psi_{\\alpha}} = \\sum_{I=0}^d \\sum_{n=0}^s c_I^{(n)}\\hat{U}_n\\ket{\\Phi_I} $$\n", + "$$ \\ket{\\Psi} = \\sum_{\\alpha} c_{\\alpha}\\ket{\\psi_{\\alpha}} = \\sum_{I=0}^d \\sum_{n=0}^s c_I^{(n)}\\hat{U}_n\\ket{\\Phi_I}. $$\n", "\n", "The energy of this state can be obtained by solving the generalized eigenvalue problem\n", - "$$ \\boldsymbol{Hc}=\\boldsymbol{Sc}E $$\n", + "$$ \\boldsymbol{Hc}=\\boldsymbol{Sc}E, $$\n", "\n", - "Where the elements of the overlap and Hamiltonian matrix are\n", + "where the elements of the overlap are\n", "\n", "$$S_{\\alpha \\beta} = \\braket{\\psi_{\\alpha}|\\psi_{\\beta}} = \\braket{\\Phi_I|\\hat{U}_m^{\\dagger}\\hat{U}_n|\\Phi_J}$$ \n", "\n", - "$$H_{\\alpha \\beta} = \\braket{\\psi_{\\alpha}|\\hat{H}|\\psi_{\\beta}} = \\braket{\\Phi_I|\\hat{U}_m^{\\dagger}\\hat{H}\\hat{U}_n|\\Phi_J}$$\n", + "and Hamiltonian matrix is\n", "\n", - "These matrix elements are computed using a quantum computer and the Hadamard test with a circuit shown below for the case of the overlap matrix elements (The Hamiltonian matrix elements circuit would include controlled application of the Hamiltonian in the circuit). Once the matrices are constructed, the diagonalization is performed classically to produce an estimate for the ground state in question.\n", + "$$H_{\\alpha \\beta} = \\braket{\\psi_{\\alpha}|\\hat{H}|\\psi_{\\beta}} = \\braket{\\Phi_I|\\hat{U}_m^{\\dagger}\\hat{H}\\hat{U}_n|\\Phi_J}.$$\n", + "\n", + "The matrix elements for $S$ are computed with the Hadamard test with a circuit shown below for the case of the overlap matrix elements. \n", "\n", "![Htest](./images/krylovcircuit.png)\n", "\n", - "The $2\\sigma_+$ term refers to measurement of the expectation value of this circuit with the $X+iY$ operator. \n" + "The $2\\sigma_+$ term refers to measurement of the expectation value of this circuit with the $X+iY$ operator.\n", + "\n", + "The Hamiltonian matrix elements are computed with a circuit that includes controlled application of the Hamiltonian. Once the $H$ and $S$ matrices are constructed, the diagonalization is performed classically to produce an estimate for the ground state in question.\n", + "\n", + "\n" ] }, { @@ -140,7 +146,7 @@ " return result\n", "\n", "\n", - "#Build the lists of coefficients and Pauli Words from H2 Hamiltonian\n", + "# Build the lists of coefficients and Pauli Words from the H2 Hamiltonian\n", "coefficient = termCoefficients(hamiltonian)\n", "pauli_string = termWords(hamiltonian)\n", "\n", @@ -153,7 +159,7 @@ "id": "74b4c079-8837-47ae-a484-52ec5f4a160e", "metadata": {}, "source": [ - "In the case of this example, the unitary operators that build the Krylov subspace are first-order Trotter operations at different time steps. The performance here could potentially be improved by increasing the size of the time step, using a higher order Trotter approximation, or using other sorts of approximations. The CUDA-Q kernels below define the unitary operations that construct the $\\psi$ basis. Each receives the target qubits, the time step, and components of the Hamiltonian." + "In this example, the unitary operators that build the Krylov subspace are first-order Trotter operations at different time steps. The performance here could potentially be improved by increasing the size of the time step, using a higher order Trotter approximation, or using other sorts of approximations. The CUDA-Q kernels below define the unitary operations that construct the $\\psi$ basis. Each receives the target qubits, the time step, and components of the Hamiltonian." ] }, { @@ -300,11 +306,11 @@ "\n", "The cell below computes the overlap matrix. This can be done in serial or in parallel, depending on the `multi_gpu` specification. First, an operator is built to apply the identity to the overlap matrix circuit when `apply_pauli` is called. Next, the `wf_overlap` array is constructed which will hold the matrix elements. \n", "\n", - "Next, a pair of nested loops, iterate over the time steps defined by the dimension of the subspace. Each m,n combination corresponds to computation of an off-diagonal matrix element of the overlap matrix $S$ using the Hadamard test. This is accomplished by calling the CUDA-Q `observe` function with the X and Y operators, along with the time steps, the components of the Hamiltonian matrix, and the initial state vector `vec`.\n", + "Next, a pair of nested loops iterate over the time steps defined by the dimension of the subspace. Each m,n combination corresponds to computation of an off-diagonal matrix element of the overlap matrix $S$ using the Hadamard test. This is accomplished by calling the CUDA-Q `observe` function with the X and Y operators, along with the time steps, the components of the Hamiltonian matrix, and the initial state vector `vec`.\n", "\n", "The observe function broadcasts over the two provided operators $X$ and $Y$ and returns a list of results. The `expectation` function returns the expectation values which are summed and stored in the matrix.\n", "\n", - "The multi-gpu case completes the same steps, expect for `observe_async` is used. This allows for the $X$ and $Y$ observables to be evaluated at the same time on two different simulated QPUs. In this case, the results are stored in lists corresponding to the real an imaginary parts, and then accessed later with the `get` command to build $S$\n" + "The multi-gpu case completes the same steps, except the `observe_async` command is used. This allows for the $X$ and $Y$ observables to be evaluated at the same time on two different simulated QPUs. In this case, the results are stored in lists corresponding to the real and imaginary parts. These are then accessed later with the `get` command to build $S$.\n" ] }, { @@ -541,19 +547,19 @@ "id": "1917bd58-4ce3-4e3e-9ccf-096577c0da14", "metadata": {}, "source": [ - "### Determining the ground state energy of the Subspace\n", + "### Determining the ground state energy of the subspace\n", "\n", "The final step is to solve the generalized eigenvaulue problem with the overlap and Hamiltonian matrices constructed using the quantum computer. The procedure begins by diagonalizing $S$ with the transform $$S = U\\Sigma U^{\\dagger}$$\n", "\n", - "The eigenvectors $v$ and eigenvalues $s$ are used to construct a new matrix $X'$\n", + "The eigenvectors $v$ and eigenvalues $s$ are used to construct a new matrix $X':$\n", "\n", - "$$ X' = S ^{\\frac{-1}{2}} = \\sum_k v_{ki} \\frac{1}{\\sqrt{s_k}} v_{kj}$$\n", + "$$ X' = S ^{\\frac{-1}{2}} = \\sum_k v_{ki} \\frac{1}{\\sqrt{s_k}} v_{kj}.$$\n", "\n", - "The $X'$ matrix diagonalizes $H$\n", + "The matrix $X'$ diagonalizes $H:$\n", "\n", - "$$ X'^{\\dagger}HX' = ES^{\\frac{1}{2}}C$$\n", + "$$ X'^{\\dagger}HX' = ES^{\\frac{1}{2}}C.$$\n", "\n", - "Using the eigenvectors of $H'$, ($^{\\frac{1}{2}}C$), the original eigenvectors to the problem can be found by left multiplying by $S^{\\frac{-1}{2}}C$" + "Using the eigenvectors of $H'$, ($^{\\frac{1}{2}}C$), the original eigenvectors to the problem can be found by left multiplying by $S^{\\frac{-1}{2}}C.$" ] }, { From c56261bc7975aadb1e309b6ab8bcf3eaa4b663e9 Mon Sep 17 00:00:00 2001 From: Ben Howe <141149032+bmhowe23@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:51:19 -0800 Subject: [PATCH 26/26] Make remote-mqpu auto-launcher aware of CUDAQ_DYNLIBS env var (#2385) Signed-off-by: Ben Howe Signed-off-by: Bettina Heim Co-authored-by: Bettina Heim --- .../cudaq/platform/mqpu/helpers/MQPUUtils.cpp | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/runtime/cudaq/platform/mqpu/helpers/MQPUUtils.cpp b/runtime/cudaq/platform/mqpu/helpers/MQPUUtils.cpp index bf36c2e1b7..bbf32ddd22 100644 --- a/runtime/cudaq/platform/mqpu/helpers/MQPUUtils.cpp +++ b/runtime/cudaq/platform/mqpu/helpers/MQPUUtils.cpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -79,6 +81,44 @@ cudaq::AutoLaunchRestServerProcess::AutoLaunchRestServerProcess( if (!serverApp) throw std::runtime_error("Unable to find CUDA-Q REST server to launch."); + // If the CUDAQ_DYNLIBS env var is set (typically from the Python + // environment), add these to the LD_LIBRARY_PATH. + std::string libPaths; + std::optional> Env; + if (auto *ch = getenv("CUDAQ_DYNLIBS")) { + Env = llvm::SmallVector(); + libPaths = ch; + if (libPaths.size() > 0) + libPaths += ":"; + + std::set libDirs; + while (libPaths.size() > 0) { + auto next_delim = libPaths.find(":"); + if (next_delim < libPaths.size()) { + std::filesystem::path lib(libPaths.substr(0, next_delim)); + libPaths = libPaths.substr(next_delim + 1); + auto libDir = lib.remove_filename().string(); + if (libDir.size() > 0) + libDirs.insert(libDir); + } + } + + std::string dynLibs = std::accumulate( + std::begin(libDirs), std::end(libDirs), std::string{}, + [](const std::string &a, const std::string &b) { return a + b + ':'; }); + dynLibs.pop_back(); + if (auto *p = getenv("LD_LIBRARY_PATH")) { + std::string envLibs = p; + if (envLibs.size() > 0) + dynLibs += ":" + envLibs; + } + for (char **env = environ; *env != nullptr; ++env) { + if (!std::string(*env).starts_with("LD_LIBRARY_PATH=")) + Env->push_back(*env); + } + Env->push_back("LD_LIBRARY_PATH=" + dynLibs); + } + constexpr std::size_t PORT_MAX_RETRIES = 10; for (std::size_t j = 0; j < PORT_MAX_RETRIES; j++) { /// Step 1: Look up a port @@ -98,9 +138,8 @@ cudaq::AutoLaunchRestServerProcess::AutoLaunchRestServerProcess( llvm::StringRef argv[] = {serverApp.get(), "--port", port.value()}; std::string errorMsg; bool executionFailed = false; - auto processInfo = - llvm::sys::ExecuteNoWait(serverApp.get(), argv, std::nullopt, {}, 0, - &errorMsg, &executionFailed); + auto processInfo = llvm::sys::ExecuteNoWait(serverApp.get(), argv, Env, {}, + 0, &errorMsg, &executionFailed); if (executionFailed) throw std::runtime_error("Failed to launch " + serverExeName + " at port " + port.value() + ": " + errorMsg);