From ae9b69f010528de8aff41f7382bb6bcb34adcace Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:05:43 -0400 Subject: [PATCH 001/101] Allow extenal googletest --- tpls/CMakeLists.txt | 82 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index ebed3400b..b4cce1f46 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -24,7 +24,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() # Disable 'deprecated-copy' warnings if the compiler recognizes the flag. -# especially for different versions of Clang/AppleClang, +# especially for different versions of Clang/AppleClang, # we don't want to set the flag on compilers that don't support it yet (errors) add_compile_flags_if_supported(-Wno-deprecated-copy) add_subdirectory(cppmicroservices) @@ -32,14 +32,14 @@ add_subdirectory(cppmicroservices) # Fix for bug #161 install(FILES "${CMAKE_BINARY_DIR}/tpls/cppmicroservices/CMakeFiles/Export/share/cppmicroservices4/cmake/CppMicroServicesTargets-release.cmake" DESTINATION share/cppmicroservices4/cmake OPTIONAL) -if (XACC_DEPS_EXTERNAL) - find_package(cpr) - if (cpr_FOUND) +if (XACC_DEPS_EXTERNAL) + find_package(cpr) + if (cpr_FOUND) set(XACC_USE_EXTERNAL_CPR TRUE) set (XACC_USE_EXTERNAL_CPR ${XACC_USE_EXTERNAL_CPR} PARENT_SCOPE) message(STATUS "${BoldGreen}cpr: Found system installation config at ${cpr_DIR}${ColorReset}") endif() -endif() +endif() if (NOT XACC_USE_EXTERNAL_CPR) set(CPR_FORCE_USE_SYSTEM_CURL ON CACHE BOOL "" FORCE) @@ -50,46 +50,54 @@ if (NOT XACC_USE_EXTERNAL_CPR) endif() # Googletest -set(BUILD_SHARED_LIBS TRUE) -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY "https://github.com/google/googletest" - GIT_TAG release-1.12.1 -) -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - -if(APPLE) - set_target_properties(gtest PROPERTIES INSTALL_RPATH "@loader_path") - set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "@loader_path") +if (XACC_DEPS_EXTERNAL) + find_package(GTest) else() - set_target_properties(gtest PROPERTIES INSTALL_RPATH "$ORIGIN") - set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "$ORIGIN") -endif() + set(BUILD_SHARED_LIBS TRUE) + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY "https://github.com/google/googletest" + GIT_TAG release-1.12.1 + ) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) -set(GTEST_FOUND TRUE) -set(GTEST_LIBRARIES gtest) -set(GTEST_MAIN_LIBRARIES gtest_main) -set(GTEST_BOTH_LIBRARIES gtest gtest_main) -set(GTEST_INCLUDE_DIRS ${googletest_SOURCE_DIR}/googletest/include) + if(APPLE) + set_target_properties(gtest PROPERTIES INSTALL_RPATH "@loader_path") + set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "@loader_path") + else() + set_target_properties(gtest PROPERTIES INSTALL_RPATH "$ORIGIN") + set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "$ORIGIN") + endif() + + set(GTEST_FOUND TRUE) + set(GTEST_LIBRARIES gtest) + set(GTEST_MAIN_LIBRARIES gtest_main) + set(GTEST_BOTH_LIBRARIES gtest gtest_main) + set(GTEST_INCLUDE_DIRS ${googletest_SOURCE_DIR}/googletest/include) -set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") -set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") -set_cache_variable(GTEST_FOUND "Set if libgtest was found or built") -set_cache_variable(GTEST_LIBRARIES "Location of libgtest") -set_cache_variable(GTEST_MAIN_LIBRARIES "Location of libgtest-main") -set_cache_variable(GTEST_BOTH_LIBRARIES "Location of both gtest libraries") -set_cache_variable(GTEST_INCLUDE_DIRS "Location of gtest include files") + set_cache_variable(GTEST_FOUND "Set if libgtest was found or built") + set_cache_variable(GTEST_LIBRARIES "Location of libgtest") + set_cache_variable(GTEST_MAIN_LIBRARIES "Location of libgtest-main") + set_cache_variable(GTEST_BOTH_LIBRARIES "Location of both gtest libraries") + set_cache_variable(GTEST_INCLUDE_DIRS "Location of gtest include files") -install(DIRECTORY "${googletest_SOURCE_DIR}/googletest/include/gtest" DESTINATION include/gtest ) + install(DIRECTORY "${googletest_SOURCE_DIR}/googletest/include/gtest" DESTINATION include/gtest ) +endif() set(BUILD_SHARED_LIBS FALSE) -set(BOOST_LIBS_OPTIONAL graph CACHE STRING "" FORCE) -add_subdirectory(boost-cmake) +if (XACC_DEPS_EXTERNAL) + find_package(Boost COMPONENTS graph) +else() + set(BOOST_LIBS_OPTIONAL graph CACHE STRING "" FORCE) + add_subdirectory(boost-cmake) +endif() -install(DIRECTORY staq DESTINATION ${CMAKE_INSTALL_PREFIX}/include) +install(DIRECTORY staq DESTINATION ${CMAKE_INSTALL_PREFIX}/include) install (DIRECTORY armadillo DESTINATION ${CMAKE_INSTALL_PREFIX}/include/) # Compiler-specific C++11 activation (FROM ANTLR4). From f2198c3a483a749969774c6a43b4b9d3fe8cb0b9 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:10:37 -0400 Subject: [PATCH 002/101] Allow external boost --- tpls/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index b4cce1f46..522781cab 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -51,7 +51,7 @@ endif() # Googletest if (XACC_DEPS_EXTERNAL) - find_package(GTest) + find_package(googletest) else() set(BUILD_SHARED_LIBS TRUE) include(FetchContent) From 03f5bc682daf900b2ef5f2a3df81f67d9255ca33 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:10:48 -0400 Subject: [PATCH 003/101] Fix missing dependency include --- quantum/plugins/algorithms/qcmx/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/quantum/plugins/algorithms/qcmx/CMakeLists.txt b/quantum/plugins/algorithms/qcmx/CMakeLists.txt index 3ff8a5f59..50702d44d 100644 --- a/quantum/plugins/algorithms/qcmx/CMakeLists.txt +++ b/quantum/plugins/algorithms/qcmx/CMakeLists.txt @@ -10,6 +10,7 @@ # Contributors: # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ +include(CheckCXXSymbolExists) set(LIBRARY_NAME xacc-algorithm-qcmx) file(GLOB SRC *.cpp) From 5d7120049475f78b9278b8598d865ed740f99dc9 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:13:33 -0400 Subject: [PATCH 004/101] Mark packages as required --- CMakeLists.txt | 24 ++++++++++++------------ tpls/CMakeLists.txt | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0431ea841..589a29852 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,13 +161,13 @@ find_package(LAPACK) # Dependencies: option(XACC_DEPS_EXTERNAL "Try find external dependencies (system installation) rather than tpls" OFF) - + set(SPDLOG_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/spdlog/include/) -if (XACC_DEPS_EXTERNAL) - find_package(spdlog) - if (spdlog_FOUND) +if (XACC_DEPS_EXTERNAL) + find_package(spdlog) + if (spdlog_FOUND) get_target_property(SPDLOG_TARGET_INC_DIR spdlog::spdlog_header_only INTERFACE_INCLUDE_DIRECTORIES) - if (EXISTS ${SPDLOG_TARGET_INC_DIR}/spdlog/spdlog.h) + if (EXISTS ${SPDLOG_TARGET_INC_DIR}/spdlog/spdlog.h) # Found a seemingly valid spdlog installation, use it when XACC_DEPS_EXTERNAL is set message(STATUS "${BoldGreen}spdlog: Found system installation at ${SPDLOG_TARGET_INC_DIR}/spdlog${ColorReset}") set(SPDLOG_INCLUDE_DIR "${SPDLOG_TARGET_INC_DIR}") @@ -176,12 +176,12 @@ if (XACC_DEPS_EXTERNAL) endif() set(NLOHMANN_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/nlohmann/single_include) -if (XACC_DEPS_EXTERNAL) - find_package(nlohmann_json) - if (nlohmann_json_FOUND) +if (XACC_DEPS_EXTERNAL) + find_package(nlohmann_json) + if (nlohmann_json_FOUND) get_target_property(NLOHMANN_TARGET_INC_DIR nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) list(GET NLOHMANN_TARGET_INC_DIR 0 NLOHMANN_TARGET_INC_DIR) - if (EXISTS ${NLOHMANN_TARGET_INC_DIR}/nlohmann/json.hpp) + if (EXISTS ${NLOHMANN_TARGET_INC_DIR}/nlohmann/json.hpp) # Found a seemingly valid nlohmann installation, use it when XACC_DEPS_EXTERNAL is set message(STATUS "${BoldGreen}nlohmann: Found system installation at ${NLOHMANN_TARGET_INC_DIR}/nlohmann${ColorReset}") set(NLOHMANN_INCLUDE_DIR "${NLOHMANN_TARGET_INC_DIR}") @@ -190,9 +190,9 @@ if (XACC_DEPS_EXTERNAL) endif() set(EIGEN_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/tpls/eigen) -if (XACC_DEPS_EXTERNAL) - find_package(Eigen3) - if (Eigen3_FOUND) +if (XACC_DEPS_EXTERNAL) + find_package(Eigen3) + if (Eigen3_FOUND) message(STATUS "${BoldGreen}Eigen3: Found system installation (version ${EIGEN3_VERSION_STRING}) config at ${Eigen3_DIR}; include directory: ${EIGEN3_INCLUDE_DIR}.${ColorReset}") set(EIGEN_INCLUDE_DIR ${EIGEN3_INCLUDE_DIR}) endif() diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index 522781cab..af4f04230 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -33,7 +33,7 @@ add_subdirectory(cppmicroservices) install(FILES "${CMAKE_BINARY_DIR}/tpls/cppmicroservices/CMakeFiles/Export/share/cppmicroservices4/cmake/CppMicroServicesTargets-release.cmake" DESTINATION share/cppmicroservices4/cmake OPTIONAL) if (XACC_DEPS_EXTERNAL) - find_package(cpr) + find_package(cpr REQUIRED) if (cpr_FOUND) set(XACC_USE_EXTERNAL_CPR TRUE) set (XACC_USE_EXTERNAL_CPR ${XACC_USE_EXTERNAL_CPR} PARENT_SCOPE) @@ -51,7 +51,7 @@ endif() # Googletest if (XACC_DEPS_EXTERNAL) - find_package(googletest) + find_package(googletest REQUIRED) else() set(BUILD_SHARED_LIBS TRUE) include(FetchContent) @@ -91,7 +91,7 @@ endif() set(BUILD_SHARED_LIBS FALSE) if (XACC_DEPS_EXTERNAL) - find_package(Boost COMPONENTS graph) + find_package(Boost COMPONENTS graph REQUIRED) else() set(BOOST_LIBS_OPTIONAL graph CACHE STRING "" FORCE) add_subdirectory(boost-cmake) From 4f864281283b8c8509d647e5af2ab110bcea1c88 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:18:52 -0400 Subject: [PATCH 005/101] Fix gtest name --- tpls/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index af4f04230..af39a8822 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -51,7 +51,7 @@ endif() # Googletest if (XACC_DEPS_EXTERNAL) - find_package(googletest REQUIRED) + find_package(GTest REQUIRED) else() set(BUILD_SHARED_LIBS TRUE) include(FetchContent) From 9e2be866e6c165bb34be0a31554c8f79653d5a84 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 11:34:55 -0400 Subject: [PATCH 006/101] Fix scoping --- CMakeLists.txt | 9 +++++++++ tpls/CMakeLists.txt | 19 +++---------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 589a29852..141cf2e26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,15 @@ if(NOT MPI_CXX_COMPILER STREQUAL "" AND XACC_ENABLE_MPI) endif() endif() +if (XACC_DEPS_EXTERNAL) + find_package(Boost COMPONENTS graph) + find_package(cpr) + if(cpr_FOUND) + set(XACC_USE_EXTERNAL_CPR ON) + endif() + find_package(GTest) +endif() + include_directories(${CMAKE_BINARY_DIR}/tpls/cppmicroservices/include) add_subdirectory(tpls) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index af39a8822..6f5706438 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -32,16 +32,7 @@ add_subdirectory(cppmicroservices) # Fix for bug #161 install(FILES "${CMAKE_BINARY_DIR}/tpls/cppmicroservices/CMakeFiles/Export/share/cppmicroservices4/cmake/CppMicroServicesTargets-release.cmake" DESTINATION share/cppmicroservices4/cmake OPTIONAL) -if (XACC_DEPS_EXTERNAL) - find_package(cpr REQUIRED) - if (cpr_FOUND) - set(XACC_USE_EXTERNAL_CPR TRUE) - set (XACC_USE_EXTERNAL_CPR ${XACC_USE_EXTERNAL_CPR} PARENT_SCOPE) - message(STATUS "${BoldGreen}cpr: Found system installation config at ${cpr_DIR}${ColorReset}") - endif() -endif() - -if (NOT XACC_USE_EXTERNAL_CPR) +if (NOT cpr_FOUND) set(CPR_FORCE_USE_SYSTEM_CURL ON CACHE BOOL "" FORCE) set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) @@ -50,9 +41,7 @@ if (NOT XACC_USE_EXTERNAL_CPR) endif() # Googletest -if (XACC_DEPS_EXTERNAL) - find_package(GTest REQUIRED) -else() +if (NOT GTest_FOUND) set(BUILD_SHARED_LIBS TRUE) include(FetchContent) FetchContent_Declare( @@ -90,9 +79,7 @@ else() endif() set(BUILD_SHARED_LIBS FALSE) -if (XACC_DEPS_EXTERNAL) - find_package(Boost COMPONENTS graph REQUIRED) -else() +if (NOT Boost_FOUND) set(BOOST_LIBS_OPTIONAL graph CACHE STRING "" FORCE) add_subdirectory(boost-cmake) endif() From d6c9f0d46ebd3e545672bcf8b6c821e01a8f58c2 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 13:19:11 -0400 Subject: [PATCH 007/101] Fix cpr link --- quantum/plugins/ibm/CMakeLists.txt | 4 ++-- quantum/plugins/rigetti/qcs/CMakeLists.txt | 2 +- quantum/plugins/rigetti/quilc/CMakeLists.txt | 2 +- xacc/CMakeLists.txt | 10 +--------- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index fa1674093..2565b7ec5 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -43,12 +43,12 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include) #${CMAKE_SOURCE_DIR}/tpls/exprtk - + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate ${ANTLR_LIB} - CppMicroServices PRIVATE cpr) + CppMicroServices PRIVATE cpr::cpr) set(_bundle_name xacc_ibm) diff --git a/quantum/plugins/rigetti/qcs/CMakeLists.txt b/quantum/plugins/rigetti/qcs/CMakeLists.txt index d886cce08..b040cd789 100644 --- a/quantum/plugins/rigetti/qcs/CMakeLists.txt +++ b/quantum/plugins/rigetti/qcs/CMakeLists.txt @@ -18,7 +18,7 @@ if(Python_FOUND) PUBLIC .. ${XACC_ROOT}/include ${EIGEN_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/tpls/pybind11/include ${Python_INCLUDE_DIRS}) - target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate cpr + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate cpr::cpr Python::Python) set(_bundle_name xacc_rigetti_qcs) diff --git a/quantum/plugins/rigetti/quilc/CMakeLists.txt b/quantum/plugins/rigetti/quilc/CMakeLists.txt index 158ee4489..680d312d0 100644 --- a/quantum/plugins/rigetti/quilc/CMakeLists.txt +++ b/quantum/plugins/rigetti/quilc/CMakeLists.txt @@ -23,7 +23,7 @@ target_include_directories( ${LIBRARY_NAME} PUBLIC .) -target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE cpr) +target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE cpr::cpr) set(_bundle_name xacc_quilc) set_target_properties(${LIBRARY_NAME} diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index 6c9f1bc7d..6fe1a1add 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -47,15 +47,7 @@ add_library(xacc SHARED service/xacc_service.cpp accelerator/remote/RemoteAccelerator.cpp) -if (XACC_USE_EXTERNAL_CPR) - # External CPR must be accompanied by CURL. - find_package(CURL REQUIRED) - set_target_properties(xacc PROPERTIES - INTERFACE_LINK_LIBRARIES "CURL::libcurl" - ) -else() - add_dependencies(xacc cpr) -endif() +target_link_libraries(xacc PUBLIC cpr::cpr) if(MPI_FOUND) include_directories(${MPI_CXX_HEADER_DIR}) From e6ec960e224b962ff48b4beb7c036adec5211d2d Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 13:20:15 -0400 Subject: [PATCH 008/101] Remove duplicate linking --- xacc/CMakeLists.txt | 102 ++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 61 deletions(-) diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index 6fe1a1add..2e5e859f7 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -21,7 +21,7 @@ install(FILES "${CMAKE_BINARY_DIR}/xacc_config.hpp" DESTINATION include/xacc) configure_file("${CMAKE_SOURCE_DIR}/xacc/xacc_version.in" "${CMAKE_BINARY_DIR}/xacc/xacc_version") install(FILES "${CMAKE_BINARY_DIR}/xacc/xacc_version" DESTINATION include/xacc) - + find_package(Libunwind) file(GLOB @@ -56,68 +56,48 @@ endif() if(LIBUNWIND_FOUND) message( STATUS "${BoldGreen}Building xacc with libunwind support.${ColorReset}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAS_LIBUNWIND") + target_compile_definitions(xacc PUBLIC "-DHAS_LIBUNWIND") target_include_directories(xacc - PRIVATE ${CMAKE_BINARY_DIR} - ${CPR_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include - ${CMAKE_SOURCE_DIR}/tpls/cxxopts - ${LIBUNWIND_INCLUDE_DIRS} - PUBLIC . - ir - compiler - program - accelerator - accelerator/remote - utils - service - algorithm - optimizer - ${CMAKE_SOURCE_DIR}/tpls/mpark-variant - ${NLOHMANN_INCLUDE_DIR} - ${SPDLOG_INCLUDE_DIR}) - - # linking against MPI libraries found by cmake - if(MPI_FOUND) - target_link_libraries(xacc - PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES} - PRIVATE cpr ${LIBUNWIND_LIBRARIES} - ${LIBUNWINDX86_LIBRARIES}) - else() - target_link_libraries(xacc - PUBLIC CppMicroServices - PRIVATE cpr ${LIBUNWIND_LIBRARIES} - ${LIBUNWINDX86_LIBRARIES}) - endif() - -else() - - target_include_directories(xacc - PRIVATE ${CMAKE_BINARY_DIR} - ${CPR_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include - ${CMAKE_SOURCE_DIR}/tpls/cxxopts - PUBLIC . - ir - compiler - program - accelerator - accelerator/remote - utils - service - algorithm - optimizer - ${CMAKE_SOURCE_DIR}/tpls/mpark-variant - ${NLOHMANN_INCLUDE_DIR} - ${SPDLOG_INCLUDE_DIR}) - - # linking against MPI libraries found by cmake - if(MPI_FOUND) - target_link_libraries(xacc PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES} PRIVATE cpr) - else() - target_link_libraries(xacc PUBLIC CppMicroServices PRIVATE cpr) - endif() + PRIVATE + ${LIBUNWIND_INCLUDE_DIRS} + ) +target_link_libraries(xacc + PRIVATE + ${LIBUNWIND_LIBRARIES} ${LIBUNWINDX86_LIBRARIES} +) +endif() +target_include_directories(xacc + PRIVATE + ${CMAKE_BINARY_DIR} + ${CPR_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include + ${CMAKE_SOURCE_DIR}/tpls/cxxopts + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ir + compiler + program + accelerator + accelerator/remote + utils + service + algorithm + optimizer + ${CMAKE_SOURCE_DIR}/tpls/mpark-variant + ${NLOHMANN_INCLUDE_DIR} + ${SPDLOG_INCLUDE_DIR} +) +target_link_libraries(xacc + PUBLIC + CppMicroServices +) + +# linking against MPI libraries found by cmake +if(MPI_FOUND) + target_link_libraries(xacc + PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES} + ) endif() target_compile_features(xacc From 96bc8dc6c3fad490d16d4dd20d9735dcb26c7c64 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 13:20:30 -0400 Subject: [PATCH 009/101] Delete bad C++ library forcing flag --- tpls/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index 6f5706438..d1f4e20a3 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -98,7 +98,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCH add_subdirectory(antlr) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") add_subdirectory(antlr) elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_SYSTEM_NAME MATCHES "Linux") execute_process( From 28fa86d45eb9a6064cef1b21b801b238d36cbfb3 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 13 Oct 2023 13:40:08 -0400 Subject: [PATCH 010/101] Use C++14 to avoid warnings --- quantum/plugins/dwave/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/dwave/CMakeLists.txt b/quantum/plugins/dwave/CMakeLists.txt index 48bff4fa6..3808e2aeb 100644 --- a/quantum/plugins/dwave/CMakeLists.txt +++ b/quantum/plugins/dwave/CMakeLists.txt @@ -21,7 +21,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-security") # dwave_sapi uses std::random_shuffle which is deprecated since C++17 -set_property(TARGET dwave_sapi PROPERTY CXX_STANDARD 11) +set_property(TARGET dwave_sapi PROPERTY CXX_STANDARD 14) file(GLOB SRC accelerator/DWave.cpp DWaveActivator.cpp @@ -90,4 +90,4 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) #file(GLOB PYDECORATORS ${CMAKE_CURRENT_SOURCE_DIR}/decorators/*.py) #install(FILES ${PYDECORATORS} DESTINATION ${CMAKE_INSTALL_PREFIX}/py-plugins) -#add_subdirectory(ir) \ No newline at end of file +#add_subdirectory(ir) From c6acbcff03f744752ea341d475340396e9f9a5d1 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 16 Oct 2023 11:04:32 -0400 Subject: [PATCH 011/101] Require older nljson to avoid build errors --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 141cf2e26..ca1813fb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,9 +186,9 @@ endif() set(NLOHMANN_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/nlohmann/single_include) if (XACC_DEPS_EXTERNAL) - find_package(nlohmann_json) + find_package(nlohmann_json 3.1) if (nlohmann_json_FOUND) - get_target_property(NLOHMANN_TARGET_INC_DIR nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(NLOHMANN_TARGET_INC_DIR nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) list(GET NLOHMANN_TARGET_INC_DIR 0 NLOHMANN_TARGET_INC_DIR) if (EXISTS ${NLOHMANN_TARGET_INC_DIR}/nlohmann/json.hpp) # Found a seemingly valid nlohmann installation, use it when XACC_DEPS_EXTERNAL is set From e6c15976406009de508ac5f52d893903896164e6 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 16 Oct 2023 11:04:40 -0400 Subject: [PATCH 012/101] fixup! Fix cpr link --- quantum/plugins/honeywell/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/honeywell/CMakeLists.txt b/quantum/plugins/honeywell/CMakeLists.txt index 9b90b2e5f..d54eebaf8 100644 --- a/quantum/plugins/honeywell/CMakeLists.txt +++ b/quantum/plugins/honeywell/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories(${LIBRARY_NAME} PUBLIC .) -target_link_libraries(${LIBRARY_NAME} PUBLIC xacc cpr) +target_link_libraries(${LIBRARY_NAME} PUBLIC xacc cpr::cpr) set(_bundle_name xacc_honeywell) set_target_properties(${LIBRARY_NAME} @@ -49,7 +49,7 @@ else() set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") endif() -if (XACC_BUILD_TESTS) +if (XACC_BUILD_TESTS) #add_subdirectory(tests) endif() From d020914cf417e563696b6890b3e288b7a4367adc Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 16 Oct 2023 11:06:50 -0400 Subject: [PATCH 013/101] Add fixes from submodules --- quantum/plugins/dwave/tpls/legacy-sapi-clients | 2 +- tpls/cppmicroservices | 2 +- xacc/optimizer/nlopt-optimizers/nlopt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/dwave/tpls/legacy-sapi-clients b/quantum/plugins/dwave/tpls/legacy-sapi-clients index 1956de9a1..d20e43d1e 160000 --- a/quantum/plugins/dwave/tpls/legacy-sapi-clients +++ b/quantum/plugins/dwave/tpls/legacy-sapi-clients @@ -1 +1 @@ -Subproject commit 1956de9a1d3e2e442597e48e8396a3564b05420c +Subproject commit d20e43d1e13706d552b7d60987375e81c452063d diff --git a/tpls/cppmicroservices b/tpls/cppmicroservices index 3dfb92faa..98ac35a6f 160000 --- a/tpls/cppmicroservices +++ b/tpls/cppmicroservices @@ -1 +1 @@ -Subproject commit 3dfb92faa2bd8e281d2ca85acccdf7eb93b9a442 +Subproject commit 98ac35a6f6ffc70bd7701dcfc6b78e35537930fa diff --git a/xacc/optimizer/nlopt-optimizers/nlopt b/xacc/optimizer/nlopt-optimizers/nlopt index 945d055b9..c2ffc4002 160000 --- a/xacc/optimizer/nlopt-optimizers/nlopt +++ b/xacc/optimizer/nlopt-optimizers/nlopt @@ -1 +1 @@ -Subproject commit 945d055b98be2db327f694b36ba507c41e1955fc +Subproject commit c2ffc40024d160a829f63ac6b5ab23c4abfe78ef From 5f8a34f602e1cdd5dfa92f411360a1b58eb546ff Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:14:39 -0500 Subject: [PATCH 014/101] Update Honeywell url --- quantum/plugins/honeywell/honeywell.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/honeywell/honeywell.hpp b/quantum/plugins/honeywell/honeywell.hpp index d9462160e..2a13d7e6c 100644 --- a/quantum/plugins/honeywell/honeywell.hpp +++ b/quantum/plugins/honeywell/honeywell.hpp @@ -116,7 +116,7 @@ class HoneywellAccelerator : public Accelerator { int shots = 1024; std::string backend = ""; bool initialized = false; - static inline const std::string url = "https://qapi.honeywell.com/v1/"; + static inline const std::string url = "https://qapi.quantinuum.com/v1/"; // List of backend names: std::vector available_backends; std::string post(const std::string &_url, const std::string &path, From 824abed2b3839bb2fc66df7d02298778c1252a4d Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:22:42 -0500 Subject: [PATCH 015/101] Update IonQ backend info --- quantum/plugins/ionq/ionq_accelerator.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/ionq/ionq_accelerator.cpp b/quantum/plugins/ionq/ionq_accelerator.cpp index bb5e9fb90..20726a79f 100644 --- a/quantum/plugins/ionq/ionq_accelerator.cpp +++ b/quantum/plugins/ionq/ionq_accelerator.cpp @@ -41,9 +41,9 @@ void IonQAccelerator::initialize(const HeterogeneousMap ¶ms) { headers.insert({"Authorization", "apiKey " + apiKey}); headers.insert({"Content-Type", "application/json"}); - auto calibrations = restClient->get(url, "/calibrations", headers); - auto j = nlohmann::json::parse(calibrations); - m_connectivity = j["calibrations"][0]["connectivity"].get>>(); + auto characterizations = restClient->get(url, "/characterizations/backends/qpu.harmony", headers); + auto j = nlohmann::json::parse(characterizations); + m_connectivity = j["characterizations"][0]["connectivity"].get>>(); remoteUrl = url; postPath = "/jobs"; @@ -144,8 +144,9 @@ void IonQAccelerator::processResponse(std::shared_ptr buffer, // End the color log std::cout << "\033[0m" << "\n"; - std::map histogram = - j["data"]["histogram"].get>(); + auto results = handleExceptionRestClientGet(url, "/jobs/" + jobId + "/results", headers); + + std::map histogram = json::parse(results); int n = buffer->size(); auto getBitStrForInt = [&](std::uint64_t i) { From 739819e344bd54ea492dbc9d291e7c2841a53477 Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:23:43 -0500 Subject: [PATCH 016/101] Add IonQ bell example --- quantum/examples/base_api/CMakeLists.txt | 5 +++- quantum/examples/base_api/bell_ionq.cpp | 29 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 quantum/examples/base_api/bell_ionq.cpp diff --git a/quantum/examples/base_api/CMakeLists.txt b/quantum/examples/base_api/CMakeLists.txt index 49238c4f0..e20b82829 100644 --- a/quantum/examples/base_api/CMakeLists.txt +++ b/quantum/examples/base_api/CMakeLists.txt @@ -36,4 +36,7 @@ add_executable(optimal_control_goat optimal_control_goat.cpp) target_link_libraries(optimal_control_goat PRIVATE xacc) add_executable(bell_azure bell_azure.cpp) -target_link_libraries(bell_azure PRIVATE xacc) \ No newline at end of file +target_link_libraries(bell_azure PRIVATE xacc) + +add_executable(bell_ionq bell_ionq.cpp) +target_link_libraries(bell_ionq PRIVATE xacc) diff --git a/quantum/examples/base_api/bell_ionq.cpp b/quantum/examples/base_api/bell_ionq.cpp new file mode 100644 index 000000000..b7407c601 --- /dev/null +++ b/quantum/examples/base_api/bell_ionq.cpp @@ -0,0 +1,29 @@ + +#include "xacc.hpp" + +int main(int argc, char **argv) { + xacc::Initialize(argc, argv); + + // Get reference to the Accelerator + auto accelerator = xacc::getAccelerator("ionq", {{"shots", 1024}}); + + // Allocate some qubits + auto buffer = xacc::qalloc(2); + + xacc::qasm(R"( +.compiler xasm +.circuit ansatz +.qbit q +H(q[0]); +CX(q[0],q[1]); +Measure(q[0]); +Measure(q[1]); +)"); + auto ansatz = xacc::getCompiled("ansatz"); + + accelerator->execute(buffer, ansatz); + + xacc::Finalize(); + + return 0; +} From e6fa8059a3f9090baad5206ab22b132233f9d148 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 24 May 2024 10:13:02 +0000 Subject: [PATCH 017/101] Turned annealing deprecated Signed-off-by: Daniel Claudino --- CMakeLists.txt | 6 ++++++ python/compiler/CMakeLists.txt | 6 +++++- python/compiler/pyxasm_listener.cpp | 11 +++++++++-- quantum/CMakeLists.txt | 4 +++- quantum/plugins/CMakeLists.txt | 5 ++++- quantum/plugins/placement/CMakeLists.txt | 4 +++- quantum/provider/CMakeLists.txt | 6 +++++- quantum/provider/QuantumIRProvider.cpp | 24 ++++++++++++++++++------ 8 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0431ea841..df065196a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,12 @@ option(XACC_BUILD_TESTS "Build test programs" OFF) option(XACC_BUILD_EXAMPLES "Build example programs" OFF) option(XACC_ENSMALLEN_INCLUDE_DIR "Path to ensmallen.hpp for mlpack optimizer" "") option(XACC_ARMADILLO_INCLUDE_DIR "Path to armadillo header for mlpack optimizer" "") +option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) +if(XACC_BUILD_ANNEALING) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") +else() + message(STATUS "${BoldYellow}Skipping Annealing libraries by default. You can turn it on with -DXACC_BUILD_ANNEALING=ON${ColorReset}") +endif() if(FROM_SETUP_PY AND NOT APPLE) message(STATUS "Running build from setup.py, linking to static libstdc++") diff --git a/python/compiler/CMakeLists.txt b/python/compiler/CMakeLists.txt index 619a112fc..48003c10d 100644 --- a/python/compiler/CMakeLists.txt +++ b/python/compiler/CMakeLists.txt @@ -42,7 +42,11 @@ usFunctionEmbedResources(TARGET ${LIBRARY_NAME} target_include_directories(${LIBRARY_NAME} PRIVATE . generated ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src) -target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate xacc-quantum-annealing ${ANTLR_LIB}) +if(XACC_BUILD_ANNEALING) + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate xacc-quantum-annealing ${ANTLR_LIB}) +else() + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate ${ANTLR_LIB}) +endif() if(APPLE) set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../lib") diff --git a/python/compiler/pyxasm_listener.cpp b/python/compiler/pyxasm_listener.cpp index c5637a6b3..dcc7bb194 100644 --- a/python/compiler/pyxasm_listener.cpp +++ b/python/compiler/pyxasm_listener.cpp @@ -18,7 +18,9 @@ #include "pyxasm_listener.hpp" #include "Circuit.hpp" -#include "AnnealingProgram.hpp" +#ifdef ANNEALING_ENABLED + #include "AnnealingProgram.hpp" +#endif #include #include @@ -49,12 +51,15 @@ void PyXASMListener::enterInstruction(pyxasmParser::InstructionContext *ctx) { instructionName = "CNOT"; } else if (instructionName == "MEASURE") { instructionName = "Measure"; - } else if (instructionName == "dwqmi") { + } +#ifdef ANNEALING_ENABLED + else if (instructionName == "dwqmi") { auto isCircuit = std::dynamic_pointer_cast(function); if (isCircuit) { function = irProvider->createComposite(function->name(), function->getVariables(), "anneal"); } } +#endif auto nRequiredBits = irProvider->getNRequiredBits(instructionName); std::vector bits; @@ -122,9 +127,11 @@ void PyXASMListener::enterInstruction(pyxasmParser::InstructionContext *ctx) { } } +#ifdef ANNEALING_ENABLED if (std::dynamic_pointer_cast(tmpInst) && std::dynamic_pointer_cast(function)) { function = irProvider->createComposite(function->name(), function->getVariables(), "anneal"); } +#endif } function->addInstruction(tmpInst); function->expand(options); diff --git a/quantum/CMakeLists.txt b/quantum/CMakeLists.txt index a10217f6f..e701d9ce7 100644 --- a/quantum/CMakeLists.txt +++ b/quantum/CMakeLists.txt @@ -11,7 +11,9 @@ # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ add_subdirectory(gate) -add_subdirectory(annealing) +if (XACC_BUILD_ANNEALING) + add_subdirectory(annealing) +endif() add_subdirectory(provider) add_subdirectory(observable) add_subdirectory(plugins) diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index 7e6681714..38701ba1f 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -13,7 +13,6 @@ add_subdirectory(ibm) add_subdirectory(rigetti) #add_subdirectory(cmr) -add_subdirectory(dwave) add_subdirectory(algorithms) add_subdirectory(decorators) add_subdirectory(circuits) @@ -37,6 +36,10 @@ else() message("-- Could NOT find Qrack library (missing: find_library(QRACK_LIBRARY NAMES qrack))") endif() +if(XACC_BUILD_ANNEALING) + add_subdirectory(dwave) +endif() + add_subdirectory(optimal_control) add_subdirectory(qsim) add_subdirectory(atos_qlm) diff --git a/quantum/plugins/placement/CMakeLists.txt b/quantum/plugins/placement/CMakeLists.txt index f1229a7c7..0f85256f2 100644 --- a/quantum/plugins/placement/CMakeLists.txt +++ b/quantum/plugins/placement/CMakeLists.txt @@ -1,4 +1,6 @@ -add_subdirectory(minor_graph_embedding) +if(XACC_BUILD_ANNEALING) + add_subdirectory(minor_graph_embedding) +endif() # Note: TriQ depends on Z3 library. # Users need to install Z3, e.g. diff --git a/quantum/provider/CMakeLists.txt b/quantum/provider/CMakeLists.txt index b48b0eb64..b83d16ba4 100644 --- a/quantum/provider/CMakeLists.txt +++ b/quantum/provider/CMakeLists.txt @@ -50,7 +50,11 @@ usFunctionEmbedResources(TARGET FILES manifest.json) -target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE xacc-quantum-gate xacc-quantum-annealing) +if(XACC_BUILD_ANNEALING) + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE xacc-quantum-gate xacc-quantum-annealing) +else() + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE xacc-quantum-gate) +endif() target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_14 diff --git a/quantum/provider/QuantumIRProvider.cpp b/quantum/provider/QuantumIRProvider.cpp index 30cb6474e..b1faf123c 100644 --- a/quantum/provider/QuantumIRProvider.cpp +++ b/quantum/provider/QuantumIRProvider.cpp @@ -15,8 +15,10 @@ #include "GateIR.hpp" #include "Circuit.hpp" -#include "DWIR.hpp" -#include "AnnealingProgram.hpp" +#ifdef ANNEALING_ENABLED + #include "DWIR.hpp" + #include "AnnealingProgram.hpp" +#endif #include "CompositeInstruction.hpp" #include "xacc_service.hpp" @@ -131,9 +133,13 @@ std::shared_ptr QuantumIRProvider::createInstruction( // FIXME, update to handle D-Wave... if (type == "circuit") { return std::make_shared(name,variables); - } else if (type == "anneal") { + } +#ifdef ANNEALING_ENABLED + else if (type == "anneal") { return std::make_shared(name,variables); - } else { + } +#endif + else { xacc::error("Invalid Composite type, can be circuit or anneal"); return nullptr; } @@ -142,9 +148,15 @@ std::shared_ptr QuantumIRProvider::createInstruction( std::shared_ptr QuantumIRProvider::createIR(const std::string type) { if (type == "circuit") { return std::make_shared(); -} else if (type == "anneal") { +} + +#ifdef ANNEALING_ENABLED +else if (type == "anneal") { return std::make_shared(); -} else { +} +#endif + +else { xacc::error("Invalid IR type, can be circuit or anneal"); return nullptr; } From bbca6f6e0220941eb4b7cb8e0a52053273f4dc1d Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 30 May 2024 19:31:31 +0000 Subject: [PATCH 018/101] Updated Boost submodule Signed-off-by: Daniel Claudino --- tpls/boost-cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/boost-cmake b/tpls/boost-cmake index 29b401f80..be32761fb 160000 --- a/tpls/boost-cmake +++ b/tpls/boost-cmake @@ -1 +1 @@ -Subproject commit 29b401f802739f076d0683c3d59696187617b198 +Subproject commit be32761fb35199ef712f285697e9146c75559608 From e47d47b53d1cd61c774a658560cd52332646bb0c Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 31 May 2024 15:49:18 +0000 Subject: [PATCH 019/101] Moved optimizers into quantum/plugins Signed-off-by: Daniel Claudino --- .gitmodules | 4 +- quantum/plugins/CMakeLists.txt | 1 + .../plugins/circuit_optimizers/CMakeLists.txt | 63 ++++++++++++++++++ .../OptimizersActivator.cpp | 0 .../gate_merge/GateMergeOptimizer.cpp | 0 .../gate_merge/GateMergeOptimizer.hpp | 0 .../gate_merge/tests/CMakeLists.txt | 0 .../gate_merge/tests/GateMergingTester.cpp | 0 .../NearestNeighborTransform.cpp | 0 .../NearestNeighborTransform.hpp | 0 .../lnn_transform/tests/CMakeLists.txt | 0 .../tests/NearestNeighborTransformTester.cpp | 0 .../manifest.json | 0 .../pulse/PulseTransform.cpp | 0 .../pulse/PulseTransform.hpp | 0 .../pulse/tests/CMakeLists.txt | 0 .../pulse/tests/PulseTransformTester.cpp | 0 .../qsearch/CMakeLists.txt | 0 .../qsearch/manifest.json | 0 .../qsearch/qsearch.cpp | 0 .../qsearch/qsearch.hpp | 0 .../qsearch/tests/CMakeLists.txt | 0 .../qsearch/tests/QsearchOptimizerTester.cpp | 0 .../simple/CircuitOptimizer.cpp | 0 .../simple/CircuitOptimizer.hpp | 0 .../simple/PhasePolynomialRepresentation.cpp | 0 .../simple/PhasePolynomialRepresentation.hpp | 0 .../simple/default_placement.hpp | 0 .../simple/tests/CMakeLists.txt | 0 .../simple/tests/CircuitOptimizerTester.cpp | 0 quantum/plugins/optimizers/CMakeLists.txt | 65 +------------------ .../plugins/optimizers}/mlpack/CMakeLists.txt | 0 .../plugins/optimizers}/mlpack/manifest.json | 0 .../optimizers}/mlpack/mlpack_optimizer.cpp | 0 .../optimizers}/mlpack/mlpack_optimizer.hpp | 0 .../optimizers}/mlpack/tests/CMakeLists.txt | 0 .../mlpack/tests/MLPACKOptimizerTester.cpp | 0 .../nlopt-optimizers/CMakeLists.txt | 4 +- .../nlopt-optimizers/manifest.json | 0 .../nlopt-optimizers/nlopt_optimizer.cpp | 0 .../nlopt-optimizers/nlopt_optimizer.hpp | 0 .../nlopt-optimizers/tests/CMakeLists.txt | 0 .../tests/NLOptimizerTester.cpp | 2 +- .../optimizer/nlopt-optimizers => tpls}/nlopt | 0 xacc/CMakeLists.txt | 1 - xacc/optimizer/CMakeLists.txt | 2 - 46 files changed, 71 insertions(+), 71 deletions(-) create mode 100644 quantum/plugins/circuit_optimizers/CMakeLists.txt rename quantum/plugins/{optimizers => circuit_optimizers}/OptimizersActivator.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/gate_merge/GateMergeOptimizer.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/gate_merge/GateMergeOptimizer.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/gate_merge/tests/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/gate_merge/tests/GateMergingTester.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/lnn_transform/NearestNeighborTransform.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/lnn_transform/NearestNeighborTransform.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/lnn_transform/tests/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/lnn_transform/tests/NearestNeighborTransformTester.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/manifest.json (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/pulse/PulseTransform.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/pulse/PulseTransform.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/pulse/tests/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/pulse/tests/PulseTransformTester.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/manifest.json (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/qsearch.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/qsearch.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/tests/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/qsearch/tests/QsearchOptimizerTester.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/CircuitOptimizer.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/CircuitOptimizer.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/PhasePolynomialRepresentation.cpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/PhasePolynomialRepresentation.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/default_placement.hpp (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/tests/CMakeLists.txt (100%) rename quantum/plugins/{optimizers => circuit_optimizers}/simple/tests/CircuitOptimizerTester.cpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/CMakeLists.txt (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/manifest.json (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/mlpack_optimizer.cpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/mlpack_optimizer.hpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/tests/CMakeLists.txt (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/mlpack/tests/MLPACKOptimizerTester.cpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/CMakeLists.txt (93%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/manifest.json (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/nlopt_optimizer.cpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/nlopt_optimizer.hpp (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/tests/CMakeLists.txt (100%) rename {xacc/optimizer => quantum/plugins/optimizers}/nlopt-optimizers/tests/NLOptimizerTester.cpp (98%) rename {xacc/optimizer/nlopt-optimizers => tpls}/nlopt (100%) delete mode 100644 xacc/optimizer/CMakeLists.txt diff --git a/.gitmodules b/.gitmodules index 0112cbde7..69b9dd425 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,8 +10,8 @@ [submodule "quantum/plugins/dwave/embedding/minorminer"] path = quantum/plugins/dwave/embedding/minorminer url = https://github.com/dwavesystems/minorminer -[submodule "xacc/optimizer/nlopt-optimizers/nlopt"] - path = xacc/optimizer/nlopt-optimizers/nlopt +[submodule "tpls/nlopt"] + path = tpls/nlopt url = https://github.com/stevengj/nlopt [submodule "quantum/plugins/dwave/tpls/legacy-sapi-clients"] path = quantum/plugins/dwave/tpls/legacy-sapi-clients diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index 38701ba1f..c837b148d 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -17,6 +17,7 @@ add_subdirectory(algorithms) add_subdirectory(decorators) add_subdirectory(circuits) add_subdirectory(optimizers) +add_subdirectory(circuit_optimizers) add_subdirectory(iontrap) add_subdirectory(ionq) add_subdirectory(placement) diff --git a/quantum/plugins/circuit_optimizers/CMakeLists.txt b/quantum/plugins/circuit_optimizers/CMakeLists.txt new file mode 100644 index 000000000..95a2555dc --- /dev/null +++ b/quantum/plugins/circuit_optimizers/CMakeLists.txt @@ -0,0 +1,63 @@ +# ******************************************************************************* +# Copyright (c) 2019 UT-Battelle, LLC. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Eclipse Distribution License v.10 which accompany this distribution. +# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html +# and the Eclipse Distribution License is available at +# https://eclipse.org/org/documents/edl-v10.php +# +# Contributors: +# Alexander J. McCaskey - initial API and implementation +# *******************************************************************************/ +set (LIBRARY_NAME xacc-circuit-optimizers) + +file (GLOB_RECURSE HEADERS *.hpp) +file (GLOB SRC simple/*.cpp OptimizersActivator.cpp pulse/*.cpp gate_merge/*.cpp lnn_transform/*.cpp) + +# Set up dependencies to resources to track changes +usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC) +# Generate bundle initialization code +usFunctionGenerateBundleInit(TARGET ${LIBRARY_NAME} OUT SRC) + +add_library(${LIBRARY_NAME} SHARED ${SRC}) + +set(_bundle_name xacc_circuit_optimizers) + +set_target_properties(${LIBRARY_NAME} PROPERTIES + # This is required for every bundle + COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_name} + # This is for convenience, used by other CMake functions + US_BUNDLE_NAME ${_bundle_name} + ) + +# Embed meta-data from a manifest.json file +usFunctionEmbedResources(TARGET ${LIBRARY_NAME} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + FILES + manifest.json + ) + +target_include_directories(${LIBRARY_NAME} PUBLIC simple pulse gate_merge lnn_transform ${EIGEN_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/tpls/exprtk) +target_link_libraries(${LIBRARY_NAME} xacc xacc-quantum-gate) + +if(APPLE) + set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../lib;@loader_path") + set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +else() + set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN") + set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") +endif() + +install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) + +# Gather tests +if(XACC_BUILD_TESTS) + add_subdirectory(simple/tests) + add_subdirectory(pulse/tests) + add_subdirectory(gate_merge/tests) + add_subdirectory(lnn_transform/tests) +endif() + +add_subdirectory(qsearch) \ No newline at end of file diff --git a/quantum/plugins/optimizers/OptimizersActivator.cpp b/quantum/plugins/circuit_optimizers/OptimizersActivator.cpp similarity index 100% rename from quantum/plugins/optimizers/OptimizersActivator.cpp rename to quantum/plugins/circuit_optimizers/OptimizersActivator.cpp diff --git a/quantum/plugins/optimizers/gate_merge/GateMergeOptimizer.cpp b/quantum/plugins/circuit_optimizers/gate_merge/GateMergeOptimizer.cpp similarity index 100% rename from quantum/plugins/optimizers/gate_merge/GateMergeOptimizer.cpp rename to quantum/plugins/circuit_optimizers/gate_merge/GateMergeOptimizer.cpp diff --git a/quantum/plugins/optimizers/gate_merge/GateMergeOptimizer.hpp b/quantum/plugins/circuit_optimizers/gate_merge/GateMergeOptimizer.hpp similarity index 100% rename from quantum/plugins/optimizers/gate_merge/GateMergeOptimizer.hpp rename to quantum/plugins/circuit_optimizers/gate_merge/GateMergeOptimizer.hpp diff --git a/quantum/plugins/optimizers/gate_merge/tests/CMakeLists.txt b/quantum/plugins/circuit_optimizers/gate_merge/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/gate_merge/tests/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/gate_merge/tests/CMakeLists.txt diff --git a/quantum/plugins/optimizers/gate_merge/tests/GateMergingTester.cpp b/quantum/plugins/circuit_optimizers/gate_merge/tests/GateMergingTester.cpp similarity index 100% rename from quantum/plugins/optimizers/gate_merge/tests/GateMergingTester.cpp rename to quantum/plugins/circuit_optimizers/gate_merge/tests/GateMergingTester.cpp diff --git a/quantum/plugins/optimizers/lnn_transform/NearestNeighborTransform.cpp b/quantum/plugins/circuit_optimizers/lnn_transform/NearestNeighborTransform.cpp similarity index 100% rename from quantum/plugins/optimizers/lnn_transform/NearestNeighborTransform.cpp rename to quantum/plugins/circuit_optimizers/lnn_transform/NearestNeighborTransform.cpp diff --git a/quantum/plugins/optimizers/lnn_transform/NearestNeighborTransform.hpp b/quantum/plugins/circuit_optimizers/lnn_transform/NearestNeighborTransform.hpp similarity index 100% rename from quantum/plugins/optimizers/lnn_transform/NearestNeighborTransform.hpp rename to quantum/plugins/circuit_optimizers/lnn_transform/NearestNeighborTransform.hpp diff --git a/quantum/plugins/optimizers/lnn_transform/tests/CMakeLists.txt b/quantum/plugins/circuit_optimizers/lnn_transform/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/lnn_transform/tests/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/lnn_transform/tests/CMakeLists.txt diff --git a/quantum/plugins/optimizers/lnn_transform/tests/NearestNeighborTransformTester.cpp b/quantum/plugins/circuit_optimizers/lnn_transform/tests/NearestNeighborTransformTester.cpp similarity index 100% rename from quantum/plugins/optimizers/lnn_transform/tests/NearestNeighborTransformTester.cpp rename to quantum/plugins/circuit_optimizers/lnn_transform/tests/NearestNeighborTransformTester.cpp diff --git a/quantum/plugins/optimizers/manifest.json b/quantum/plugins/circuit_optimizers/manifest.json similarity index 100% rename from quantum/plugins/optimizers/manifest.json rename to quantum/plugins/circuit_optimizers/manifest.json diff --git a/quantum/plugins/optimizers/pulse/PulseTransform.cpp b/quantum/plugins/circuit_optimizers/pulse/PulseTransform.cpp similarity index 100% rename from quantum/plugins/optimizers/pulse/PulseTransform.cpp rename to quantum/plugins/circuit_optimizers/pulse/PulseTransform.cpp diff --git a/quantum/plugins/optimizers/pulse/PulseTransform.hpp b/quantum/plugins/circuit_optimizers/pulse/PulseTransform.hpp similarity index 100% rename from quantum/plugins/optimizers/pulse/PulseTransform.hpp rename to quantum/plugins/circuit_optimizers/pulse/PulseTransform.hpp diff --git a/quantum/plugins/optimizers/pulse/tests/CMakeLists.txt b/quantum/plugins/circuit_optimizers/pulse/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/pulse/tests/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/pulse/tests/CMakeLists.txt diff --git a/quantum/plugins/optimizers/pulse/tests/PulseTransformTester.cpp b/quantum/plugins/circuit_optimizers/pulse/tests/PulseTransformTester.cpp similarity index 100% rename from quantum/plugins/optimizers/pulse/tests/PulseTransformTester.cpp rename to quantum/plugins/circuit_optimizers/pulse/tests/PulseTransformTester.cpp diff --git a/quantum/plugins/optimizers/qsearch/CMakeLists.txt b/quantum/plugins/circuit_optimizers/qsearch/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/qsearch/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/qsearch/CMakeLists.txt diff --git a/quantum/plugins/optimizers/qsearch/manifest.json b/quantum/plugins/circuit_optimizers/qsearch/manifest.json similarity index 100% rename from quantum/plugins/optimizers/qsearch/manifest.json rename to quantum/plugins/circuit_optimizers/qsearch/manifest.json diff --git a/quantum/plugins/optimizers/qsearch/qsearch.cpp b/quantum/plugins/circuit_optimizers/qsearch/qsearch.cpp similarity index 100% rename from quantum/plugins/optimizers/qsearch/qsearch.cpp rename to quantum/plugins/circuit_optimizers/qsearch/qsearch.cpp diff --git a/quantum/plugins/optimizers/qsearch/qsearch.hpp b/quantum/plugins/circuit_optimizers/qsearch/qsearch.hpp similarity index 100% rename from quantum/plugins/optimizers/qsearch/qsearch.hpp rename to quantum/plugins/circuit_optimizers/qsearch/qsearch.hpp diff --git a/quantum/plugins/optimizers/qsearch/tests/CMakeLists.txt b/quantum/plugins/circuit_optimizers/qsearch/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/qsearch/tests/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/qsearch/tests/CMakeLists.txt diff --git a/quantum/plugins/optimizers/qsearch/tests/QsearchOptimizerTester.cpp b/quantum/plugins/circuit_optimizers/qsearch/tests/QsearchOptimizerTester.cpp similarity index 100% rename from quantum/plugins/optimizers/qsearch/tests/QsearchOptimizerTester.cpp rename to quantum/plugins/circuit_optimizers/qsearch/tests/QsearchOptimizerTester.cpp diff --git a/quantum/plugins/optimizers/simple/CircuitOptimizer.cpp b/quantum/plugins/circuit_optimizers/simple/CircuitOptimizer.cpp similarity index 100% rename from quantum/plugins/optimizers/simple/CircuitOptimizer.cpp rename to quantum/plugins/circuit_optimizers/simple/CircuitOptimizer.cpp diff --git a/quantum/plugins/optimizers/simple/CircuitOptimizer.hpp b/quantum/plugins/circuit_optimizers/simple/CircuitOptimizer.hpp similarity index 100% rename from quantum/plugins/optimizers/simple/CircuitOptimizer.hpp rename to quantum/plugins/circuit_optimizers/simple/CircuitOptimizer.hpp diff --git a/quantum/plugins/optimizers/simple/PhasePolynomialRepresentation.cpp b/quantum/plugins/circuit_optimizers/simple/PhasePolynomialRepresentation.cpp similarity index 100% rename from quantum/plugins/optimizers/simple/PhasePolynomialRepresentation.cpp rename to quantum/plugins/circuit_optimizers/simple/PhasePolynomialRepresentation.cpp diff --git a/quantum/plugins/optimizers/simple/PhasePolynomialRepresentation.hpp b/quantum/plugins/circuit_optimizers/simple/PhasePolynomialRepresentation.hpp similarity index 100% rename from quantum/plugins/optimizers/simple/PhasePolynomialRepresentation.hpp rename to quantum/plugins/circuit_optimizers/simple/PhasePolynomialRepresentation.hpp diff --git a/quantum/plugins/optimizers/simple/default_placement.hpp b/quantum/plugins/circuit_optimizers/simple/default_placement.hpp similarity index 100% rename from quantum/plugins/optimizers/simple/default_placement.hpp rename to quantum/plugins/circuit_optimizers/simple/default_placement.hpp diff --git a/quantum/plugins/optimizers/simple/tests/CMakeLists.txt b/quantum/plugins/circuit_optimizers/simple/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/optimizers/simple/tests/CMakeLists.txt rename to quantum/plugins/circuit_optimizers/simple/tests/CMakeLists.txt diff --git a/quantum/plugins/optimizers/simple/tests/CircuitOptimizerTester.cpp b/quantum/plugins/circuit_optimizers/simple/tests/CircuitOptimizerTester.cpp similarity index 100% rename from quantum/plugins/optimizers/simple/tests/CircuitOptimizerTester.cpp rename to quantum/plugins/circuit_optimizers/simple/tests/CircuitOptimizerTester.cpp diff --git a/quantum/plugins/optimizers/CMakeLists.txt b/quantum/plugins/optimizers/CMakeLists.txt index 95a2555dc..d764e5c20 100644 --- a/quantum/plugins/optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/CMakeLists.txt @@ -1,63 +1,2 @@ -# ******************************************************************************* -# Copyright (c) 2019 UT-Battelle, LLC. -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Eclipse Public License v1.0 -# and Eclipse Distribution License v.10 which accompany this distribution. -# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html -# and the Eclipse Distribution License is available at -# https://eclipse.org/org/documents/edl-v10.php -# -# Contributors: -# Alexander J. McCaskey - initial API and implementation -# *******************************************************************************/ -set (LIBRARY_NAME xacc-circuit-optimizers) - -file (GLOB_RECURSE HEADERS *.hpp) -file (GLOB SRC simple/*.cpp OptimizersActivator.cpp pulse/*.cpp gate_merge/*.cpp lnn_transform/*.cpp) - -# Set up dependencies to resources to track changes -usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC) -# Generate bundle initialization code -usFunctionGenerateBundleInit(TARGET ${LIBRARY_NAME} OUT SRC) - -add_library(${LIBRARY_NAME} SHARED ${SRC}) - -set(_bundle_name xacc_circuit_optimizers) - -set_target_properties(${LIBRARY_NAME} PROPERTIES - # This is required for every bundle - COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_name} - # This is for convenience, used by other CMake functions - US_BUNDLE_NAME ${_bundle_name} - ) - -# Embed meta-data from a manifest.json file -usFunctionEmbedResources(TARGET ${LIBRARY_NAME} - WORKING_DIRECTORY - ${CMAKE_CURRENT_SOURCE_DIR} - FILES - manifest.json - ) - -target_include_directories(${LIBRARY_NAME} PUBLIC simple pulse gate_merge lnn_transform ${EIGEN_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/tpls/exprtk) -target_link_libraries(${LIBRARY_NAME} xacc xacc-quantum-gate) - -if(APPLE) - set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../lib;@loader_path") - set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -else() - set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN") - set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") -endif() - -install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) - -# Gather tests -if(XACC_BUILD_TESTS) - add_subdirectory(simple/tests) - add_subdirectory(pulse/tests) - add_subdirectory(gate_merge/tests) - add_subdirectory(lnn_transform/tests) -endif() - -add_subdirectory(qsearch) \ No newline at end of file +add_subdirectory(nlopt-optimizers) +add_subdirectory(mlpack) \ No newline at end of file diff --git a/xacc/optimizer/mlpack/CMakeLists.txt b/quantum/plugins/optimizers/mlpack/CMakeLists.txt similarity index 100% rename from xacc/optimizer/mlpack/CMakeLists.txt rename to quantum/plugins/optimizers/mlpack/CMakeLists.txt diff --git a/xacc/optimizer/mlpack/manifest.json b/quantum/plugins/optimizers/mlpack/manifest.json similarity index 100% rename from xacc/optimizer/mlpack/manifest.json rename to quantum/plugins/optimizers/mlpack/manifest.json diff --git a/xacc/optimizer/mlpack/mlpack_optimizer.cpp b/quantum/plugins/optimizers/mlpack/mlpack_optimizer.cpp similarity index 100% rename from xacc/optimizer/mlpack/mlpack_optimizer.cpp rename to quantum/plugins/optimizers/mlpack/mlpack_optimizer.cpp diff --git a/xacc/optimizer/mlpack/mlpack_optimizer.hpp b/quantum/plugins/optimizers/mlpack/mlpack_optimizer.hpp similarity index 100% rename from xacc/optimizer/mlpack/mlpack_optimizer.hpp rename to quantum/plugins/optimizers/mlpack/mlpack_optimizer.hpp diff --git a/xacc/optimizer/mlpack/tests/CMakeLists.txt b/quantum/plugins/optimizers/mlpack/tests/CMakeLists.txt similarity index 100% rename from xacc/optimizer/mlpack/tests/CMakeLists.txt rename to quantum/plugins/optimizers/mlpack/tests/CMakeLists.txt diff --git a/xacc/optimizer/mlpack/tests/MLPACKOptimizerTester.cpp b/quantum/plugins/optimizers/mlpack/tests/MLPACKOptimizerTester.cpp similarity index 100% rename from xacc/optimizer/mlpack/tests/MLPACKOptimizerTester.cpp rename to quantum/plugins/optimizers/mlpack/tests/MLPACKOptimizerTester.cpp diff --git a/xacc/optimizer/nlopt-optimizers/CMakeLists.txt b/quantum/plugins/optimizers/nlopt-optimizers/CMakeLists.txt similarity index 93% rename from xacc/optimizer/nlopt-optimizers/CMakeLists.txt rename to quantum/plugins/optimizers/nlopt-optimizers/CMakeLists.txt index 6cdbadc8c..e1c56ae54 100644 --- a/xacc/optimizer/nlopt-optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/nlopt-optimizers/CMakeLists.txt @@ -9,7 +9,7 @@ SET(NLOPT_SWIG OFF CACHE BOOL "") set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") endif() set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib) -add_subdirectory(nlopt) +add_subdirectory(${CMAKE_SOURCE_DIR}/tpls/nlopt ${CMAKE_BINARY_DIR}/tpls/nlopt) set(LIBRARY_NAME xacc-optimizer-nlopt) @@ -22,7 +22,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC . .. ${CMAKE_BUILD_DIR}/xacc/optimizer/nlopt-optimizers/nlopt/src/api) + PUBLIC . .. ${CMAKE_SOURCE_DIR}/tpls/nlopt/src/api) target_link_libraries(${LIBRARY_NAME} PUBLIC nlopt xacc CppMicroServices) diff --git a/xacc/optimizer/nlopt-optimizers/manifest.json b/quantum/plugins/optimizers/nlopt-optimizers/manifest.json similarity index 100% rename from xacc/optimizer/nlopt-optimizers/manifest.json rename to quantum/plugins/optimizers/nlopt-optimizers/manifest.json diff --git a/xacc/optimizer/nlopt-optimizers/nlopt_optimizer.cpp b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp similarity index 100% rename from xacc/optimizer/nlopt-optimizers/nlopt_optimizer.cpp rename to quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp diff --git a/xacc/optimizer/nlopt-optimizers/nlopt_optimizer.hpp b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.hpp similarity index 100% rename from xacc/optimizer/nlopt-optimizers/nlopt_optimizer.hpp rename to quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.hpp diff --git a/xacc/optimizer/nlopt-optimizers/tests/CMakeLists.txt b/quantum/plugins/optimizers/nlopt-optimizers/tests/CMakeLists.txt similarity index 100% rename from xacc/optimizer/nlopt-optimizers/tests/CMakeLists.txt rename to quantum/plugins/optimizers/nlopt-optimizers/tests/CMakeLists.txt diff --git a/xacc/optimizer/nlopt-optimizers/tests/NLOptimizerTester.cpp b/quantum/plugins/optimizers/nlopt-optimizers/tests/NLOptimizerTester.cpp similarity index 98% rename from xacc/optimizer/nlopt-optimizers/tests/NLOptimizerTester.cpp rename to quantum/plugins/optimizers/nlopt-optimizers/tests/NLOptimizerTester.cpp index 4560b2f47..e7578d95c 100644 --- a/xacc/optimizer/nlopt-optimizers/tests/NLOptimizerTester.cpp +++ b/quantum/plugins/optimizers/nlopt-optimizers/tests/NLOptimizerTester.cpp @@ -1,7 +1,7 @@ #include #include "xacc.hpp" #include "xacc_service.hpp" -#include "nlopt_optimizer.hpp" +//#include "nlopt_optimizer.hpp" using namespace xacc; diff --git a/xacc/optimizer/nlopt-optimizers/nlopt b/tpls/nlopt similarity index 100% rename from xacc/optimizer/nlopt-optimizers/nlopt rename to tpls/nlopt diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index 6c9f1bc7d..40f827085 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -151,7 +151,6 @@ endif() install(FILES ${HEADERS} DESTINATION include/xacc) install(TARGETS xacc DESTINATION lib) -add_subdirectory(optimizer) add_subdirectory(utils/exprtk_parsing) add_subdirectory(ir/graph-impl) add_subdirectory(utils/ini_config_parsing) diff --git a/xacc/optimizer/CMakeLists.txt b/xacc/optimizer/CMakeLists.txt deleted file mode 100644 index d764e5c20..000000000 --- a/xacc/optimizer/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(nlopt-optimizers) -add_subdirectory(mlpack) \ No newline at end of file From 187a3e7614a6adba4ced2e14b36c2de1f491fa63 Mon Sep 17 00:00:00 2001 From: Austin Adams Date: Sun, 2 Jun 2024 17:26:19 -0400 Subject: [PATCH 020/101] Build gtest only if we are building tests --- tpls/CMakeLists.txt | 62 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index ebed3400b..02db034d1 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -49,41 +49,43 @@ if (NOT XACC_USE_EXTERNAL_CPR) add_subdirectory(cpr) endif() -# Googletest -set(BUILD_SHARED_LIBS TRUE) -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY "https://github.com/google/googletest" - GIT_TAG release-1.12.1 -) -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) +if(XACC_BUILD_TESTS) + # Googletest + set(BUILD_SHARED_LIBS TRUE) + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY "https://github.com/google/googletest" + GIT_TAG release-1.12.1 + ) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) -if(APPLE) - set_target_properties(gtest PROPERTIES INSTALL_RPATH "@loader_path") - set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "@loader_path") -else() - set_target_properties(gtest PROPERTIES INSTALL_RPATH "$ORIGIN") - set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "$ORIGIN") -endif() + if(APPLE) + set_target_properties(gtest PROPERTIES INSTALL_RPATH "@loader_path") + set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "@loader_path") + else() + set_target_properties(gtest PROPERTIES INSTALL_RPATH "$ORIGIN") + set_target_properties(gtest_main PROPERTIES INSTALL_RPATH "$ORIGIN") + endif() -set(GTEST_FOUND TRUE) -set(GTEST_LIBRARIES gtest) -set(GTEST_MAIN_LIBRARIES gtest_main) -set(GTEST_BOTH_LIBRARIES gtest gtest_main) -set(GTEST_INCLUDE_DIRS ${googletest_SOURCE_DIR}/googletest/include) + set(GTEST_FOUND TRUE) + set(GTEST_LIBRARIES gtest) + set(GTEST_MAIN_LIBRARIES gtest_main) + set(GTEST_BOTH_LIBRARIES gtest gtest_main) + set(GTEST_INCLUDE_DIRS ${googletest_SOURCE_DIR}/googletest/include) -set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") -set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") -set_cache_variable(GTEST_FOUND "Set if libgtest was found or built") -set_cache_variable(GTEST_LIBRARIES "Location of libgtest") -set_cache_variable(GTEST_MAIN_LIBRARIES "Location of libgtest-main") -set_cache_variable(GTEST_BOTH_LIBRARIES "Location of both gtest libraries") -set_cache_variable(GTEST_INCLUDE_DIRS "Location of gtest include files") + set_cache_variable(GTEST_FOUND "Set if libgtest was found or built") + set_cache_variable(GTEST_LIBRARIES "Location of libgtest") + set_cache_variable(GTEST_MAIN_LIBRARIES "Location of libgtest-main") + set_cache_variable(GTEST_BOTH_LIBRARIES "Location of both gtest libraries") + set_cache_variable(GTEST_INCLUDE_DIRS "Location of gtest include files") -install(DIRECTORY "${googletest_SOURCE_DIR}/googletest/include/gtest" DESTINATION include/gtest ) + install(DIRECTORY "${googletest_SOURCE_DIR}/googletest/include/gtest" DESTINATION include/gtest ) +endif() set(BUILD_SHARED_LIBS FALSE) set(BOOST_LIBS_OPTIONAL graph CACHE STRING "" FORCE) From 5329e7894b49fe33a9e7706144070ef3c903b03d Mon Sep 17 00:00:00 2001 From: Austin Adams Date: Sun, 2 Jun 2024 17:27:04 -0400 Subject: [PATCH 021/101] Allow saying find_package(XACC 1.0.0) This creates a version file so that you can specify a version for find_package(XACC), like find_package(XACC 1.0.0). For more info, see: https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-version-selection --- CMakeLists.txt | 2 ++ cmake/xacc-config-version.cmake.in | 8 ++++++++ cmake/xacc-config.cmake.in | 4 ---- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 cmake/xacc-config-version.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 0431ea841..bd242ee00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,7 +244,9 @@ set(PATCH_VERSION 0) # their CMake builds, and pass -DXACC_DIR=/path/to/install/xacc # and CMake loads include paths, libs, etc configure_file("${CMAKE_SOURCE_DIR}/cmake/xacc-config.cmake.in" "${CMAKE_BINARY_DIR}/xacc-config.cmake" @ONLY) +configure_file("${CMAKE_SOURCE_DIR}/cmake/xacc-config-version.cmake.in" "${CMAKE_BINARY_DIR}/xacc-config-version.cmake" @ONLY) install(FILES "${CMAKE_BINARY_DIR}/xacc-config.cmake" DESTINATION .) +install(FILES "${CMAKE_BINARY_DIR}/xacc-config-version.cmake" DESTINATION .) install(FILES "${CMAKE_SOURCE_DIR}/cmake/Modules/format.cmake" DESTINATION share/xacc/) install(FILES "${CMAKE_SOURCE_DIR}/tpls/mpark-variant/variant.hpp" DESTINATION include/xacc/) install(FILES "${CMAKE_SOURCE_DIR}/tpls/taocpp/operators.hpp" DESTINATION include/xacc/) diff --git a/cmake/xacc-config-version.cmake.in b/cmake/xacc-config-version.cmake.in new file mode 100644 index 000000000..f5e0851f8 --- /dev/null +++ b/cmake/xacc-config-version.cmake.in @@ -0,0 +1,8 @@ +set(PACKAGE_VERSION "@MAJOR_VERSION@.@MINOR_VERSION@.@PATCH_VERSION@") +# The quotes for the right operand are intentional here: if CMake executes this +# file without ${PACKAGE_FIND_VERSION} set, then if() will still get three +# operands. Without the quotes, if() will only get two operands in that case, +# throwing an error. +if(${PACKAGE_VERSION} VERSION_GREATER_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE 1) +endif() diff --git a/cmake/xacc-config.cmake.in b/cmake/xacc-config.cmake.in index d09ed19d1..7bd065752 100644 --- a/cmake/xacc-config.cmake.in +++ b/cmake/xacc-config.cmake.in @@ -20,11 +20,7 @@ if(NOT TARGET format) endif() # Set version info -set(XACC_VERSION_MAJOR @MAJOR_VERSION@) -set(XACC_VERSION_MINOR @MINOR_VERSION@) -set(XACC_VERSION_PATCH @PATCH_VERSION@) set(XACC_VERSION_SUFFIX @XACC_BUILD_VERSION@) -set(XACC_VERSION "@MAJOR_VERSION@.@MINOR_VERSION@.@PATCH_VERSION@-@XACC_BUILD_VERSION@") set(XACC_LIBRARY_DIR "${XACC_ROOT}/lib") From 7738f704eb1a9afa39726ad5bbfd5551eb8d9111 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 3 Jun 2024 19:38:39 +0000 Subject: [PATCH 022/101] Updated cppmicroservices Signed-off-by: Daniel Claudino --- .gitmodules | 2 +- tpls/cppmicroservices | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 69b9dd425..eebd43b46 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,7 @@ url = https://github.com/ornl-qci/boost-cmake [submodule "tpls/cppmicroservices"] path = tpls/cppmicroservices - url = https://github.com/ornl-qci/cppmicroservices + url = https://github.com/CppMicroServices/CppMicroServices [submodule "quantum/plugins/dwave/embedding/minorminer"] path = quantum/plugins/dwave/embedding/minorminer url = https://github.com/dwavesystems/minorminer diff --git a/tpls/cppmicroservices b/tpls/cppmicroservices index 3dfb92faa..899530e5b 160000 --- a/tpls/cppmicroservices +++ b/tpls/cppmicroservices @@ -1 +1 @@ -Subproject commit 3dfb92faa2bd8e281d2ca85acccdf7eb93b9a442 +Subproject commit 899530e5b6929c90479b1b6040d2a530776fc8a4 From 62d658e1bdf2c0eb5222e1ff32fb189ba9095577 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 20 Jun 2024 16:59:28 +0000 Subject: [PATCH 023/101] Implemented method to get only the basis rotations for measurements Signed-off-by: Daniel Claudino --- python/py_observable.cpp | 4 +- python/py_observable.hpp | 5 + .../observable/fermion/FermionOperator.cpp | 7 + .../observable/fermion/FermionOperator.hpp | 4 + quantum/observable/pauli/PauliOperator.cpp | 128 ++++++++++++++++++ quantum/observable/pauli/PauliOperator.hpp | 3 + .../pauli/tests/PauliOperatorTester.cpp | 11 +- xacc/ir/Observable.hpp | 2 + xacc/tests/AlgorithmTester.cpp | 5 + xacc/tests/HeterogeneousTester.cpp | 3 + 10 files changed, 170 insertions(+), 2 deletions(-) diff --git a/python/py_observable.cpp b/python/py_observable.cpp index f23246fbc..adab2a32e 100644 --- a/python/py_observable.cpp +++ b/python/py_observable.cpp @@ -12,6 +12,7 @@ *******************************************************************************/ #include "py_observable.hpp" //#include "Observable.hpp" +#include "Observable.hpp" #include "PauliOperator.hpp" #include "FermionOperator.hpp" //#include "Utils.hpp" @@ -46,7 +47,8 @@ void bind_observable(py::module &m) { xacc::Observable::fromString, "") .def("postProcess", &xacc::Observable::postProcess, - "Post-process the execution results."); + "Post-process the execution results.") + .def("getBasisRotations", &xacc::Observable::getMeasurementBasisRotations); m.def("getObservable", [](const std::string &type, diff --git a/python/py_observable.hpp b/python/py_observable.hpp index 0bfdbf9ca..aed6c26fa 100644 --- a/python/py_observable.hpp +++ b/python/py_observable.hpp @@ -21,6 +21,7 @@ #include #include +#include "Observable.hpp" #include "xacc.hpp" namespace py = pybind11; @@ -66,6 +67,10 @@ class PyObservable : public xacc::Observable { postProcessTask, extra_data); } + std::vector> getMeasurementBasisRotations() override { + PYBIND11_OVERLOAD_PURE(std::vector>, xacc::Observable, getBasisRotations); + } + }; void bind_observable(py::module& m); \ No newline at end of file diff --git a/quantum/observable/fermion/FermionOperator.cpp b/quantum/observable/fermion/FermionOperator.cpp index b9ceefa3d..cf1409fcd 100644 --- a/quantum/observable/fermion/FermionOperator.cpp +++ b/quantum/observable/fermion/FermionOperator.cpp @@ -14,7 +14,9 @@ #include #include +#include +#include "CompositeInstruction.hpp" #include "FermionListenerImpl.hpp" #include "FermionOperatorLexer.h" #include "ObservableTransform.hpp" @@ -337,6 +339,11 @@ std::shared_ptr FermionOperator::normalOrder() { return normalOrdered; } +std::vector> FermionOperator::getMeasurementBasisRotations() { + auto transform = xacc::getService("jw"); + return transform->transform(xacc::as_shared_ptr(this))->getMeasurementBasisRotations(); +} + } // namespace quantum } // namespace xacc diff --git a/quantum/observable/fermion/FermionOperator.hpp b/quantum/observable/fermion/FermionOperator.hpp index cf188eb59..c273717a5 100644 --- a/quantum/observable/fermion/FermionOperator.hpp +++ b/quantum/observable/fermion/FermionOperator.hpp @@ -195,6 +195,10 @@ class FermionOperator const HeterogeneousMap &extra_data) override; std::shared_ptr normalOrder() override; + + + std::vector> getMeasurementBasisRotations() override; + }; } // namespace quantum diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index d62122c0e..dea2b9b66 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -11,11 +11,16 @@ * Alexander J. McCaskey - initial API and implementation *******************************************************************************/ #include "PauliOperator.hpp" +#include "CompositeInstruction.hpp" #include "IRProvider.hpp" +#include +#include #include +#include #include #include #include +#include "Instruction.hpp" #include "Observable.hpp" #include "xacc.hpp" #include "xacc_service.hpp" @@ -181,6 +186,59 @@ std::complex PauliOperator::coefficient() { } return terms.begin()->second.coeff(); } + +std::vector> +PauliOperator::observe(std::shared_ptr function) { + + auto basisRotations = getMeasurementBasisRotations(); + // Create a new GateQIR to hold the spin based terms + auto gateRegistry = xacc::getService("quantum"); + std::vector> observed; + auto pi = xacc::constants::pi; + + // If the incoming function has instructions that have + // their buffer_names set, then we need to set the + // new measurement instructions buffer names to be the same. + // Here we assume that all instructions have the same buffer name + std::string buf_name = ""; + + if (function->nInstructions() > 0 && + !function->getInstruction(0)->getBufferNames().empty()) { + buf_name = function->getInstruction(0)->getBufferNames()[0]; + } + + assert(basisRotations.size() == terms.size()); + + auto it1 = basisRotations.begin(); + auto it2 = terms.begin(); + for (; it1 != basisRotations.end() && it2 != terms.end(); ++it1, ++it2) { + + Term spinInst = (*it2).second; + + auto gateFunction = + gateRegistry->createComposite((*it2).first, function->getVariables()); + + gateFunction->setCoefficient(spinInst.coeff()); + + if (function->hasChildren()) { + gateFunction->addInstruction(function->clone()); + } + + for (auto arg : function->getArguments()) { + gateFunction->addArgument(arg, 0); + } + + for (auto& rot : (*it1)->getInstructions()) { + rot->setBufferNames({buf_name}); + gateFunction->addInstruction(rot); + } + + observed.push_back(gateFunction); + } + return observed; +} + +/* std::vector> PauliOperator::observe(std::shared_ptr function) { @@ -272,6 +330,7 @@ PauliOperator::observe(std::shared_ptr function) { } return observed; } +*/ std::vector> PauliOperator::observe(std::shared_ptr function, @@ -1139,6 +1198,75 @@ double PauliOperator::postProcess(std::shared_ptr buffer, xacc::error("Unknown post-processing task: " + postProcessTask); return 0.0; } + +std::vector> PauliOperator::getMeasurementBasisRotations() { + + // the idea is that, for something like VQE, we only need to know + // the qubits that need to be measure in the X or Y basis + // so we map the index of the qubit, to the corresponding + // rotation operators, then later add measure to all qubits + std::vector> basisRotations; + + auto pi = xacc::constants::pi; + // Create a new GateQIR to hold the spin based terms + auto gateRegistry = xacc::getService("quantum"); + + // If the incoming function has instructions that have + // their buffer_names set, then we need to set the + // new measurement instructions buffer names to be the same. + // Here we assume that all instructions have the same buffer name + std::string buf_name = ""; + + // Populate GateQIR now... + for (auto &inst : terms) { + + Term spinInst = inst.second; + + // Loop over all terms in the Spin Instruction + // and create instructions to run on the Gate QPU. + auto termsMap = spinInst.ops(); + + std::vector> terms; + for (auto &kv : termsMap) { + if (kv.second != "I" && !kv.second.empty()) { + terms.push_back({kv.first, kv.second}); + } + } + auto rotationGates = gateRegistry->createComposite(inst.first); + std::vector measureIdxs; + for (int i = terms.size() - 1; i >= 0; i--) { + + std::size_t qbit = terms[i].first; + measureIdxs.push_back(qbit); + auto gateName = terms[i].second; + + if (gateName == "X") { + auto hadamard = + gateRegistry->createInstruction("H", {qbit}); + if (!buf_name.empty()) + hadamard->setBufferNames({buf_name}); + rotationGates->addInstruction(hadamard); + } else if (gateName == "Y") { + auto rx = + gateRegistry->createInstruction("Rx", {qbit}, {pi / 2.0}); + if (!buf_name.empty()) + rx->setBufferNames({buf_name}); + rotationGates->addInstruction(rx); + } + + } + for(auto& mb : measureIdxs) { + auto meas = gateRegistry->createInstruction("Measure", {mb}); + if (!buf_name.empty()) + meas->setBufferNames({buf_name}); + rotationGates->addInstruction(meas); + } + basisRotations.push_back(rotationGates); + } + + return basisRotations; +} + } // namespace quantum } // namespace xacc diff --git a/quantum/observable/pauli/PauliOperator.hpp b/quantum/observable/pauli/PauliOperator.hpp index 496f3c504..bc5bbe9a1 100644 --- a/quantum/observable/pauli/PauliOperator.hpp +++ b/quantum/observable/pauli/PauliOperator.hpp @@ -359,6 +359,9 @@ class PauliOperator virtual double postProcess(std::shared_ptr buffer, const std::string &postProcessTask, const HeterogeneousMap &extra_data) override; + + std::vector> getMeasurementBasisRotations() override; + private: double calcExpValFromGroupedExecution(std::shared_ptr buffer); diff --git a/quantum/observable/pauli/tests/PauliOperatorTester.cpp b/quantum/observable/pauli/tests/PauliOperatorTester.cpp index 471e3bd0d..00d7198e8 100644 --- a/quantum/observable/pauli/tests/PauliOperatorTester.cpp +++ b/quantum/observable/pauli/tests/PauliOperatorTester.cpp @@ -592,10 +592,19 @@ TEST(PauliOperatorTester, checkGroupingQaoaPostProcessMSB) { EXPECT_NEAR(exp_val, 2.0, 0.1); } +TEST(PauliOperatorTester, checkGetBasisRotations) { + PauliOperator op; + op.fromString("(-0.5,0) Z0 Z1 + (-0.5,0) X0 X1 + (-0.5,0) Y0 Y1"); + auto rot = op.getMeasurementBasisRotations(); + for(auto& r :rot) { + std::cout << r->toString() << "\n"; + } +} + int main(int argc, char **argv) { xacc::Initialize(argc, argv); ::testing::InitGoogleTest(&argc, argv); auto ret = RUN_ALL_TESTS(); xacc::Finalize(); return ret; -} +} \ No newline at end of file diff --git a/xacc/ir/Observable.hpp b/xacc/ir/Observable.hpp index d041af63d..cd88a1e8f 100644 --- a/xacc/ir/Observable.hpp +++ b/xacc/ir/Observable.hpp @@ -49,6 +49,8 @@ class Observable : public Identifiable { } } + virtual std::vector> getMeasurementBasisRotations() = 0; + virtual const std::string toString() = 0; virtual void fromString(const std::string str) = 0; virtual const int nBits() = 0; diff --git a/xacc/tests/AlgorithmTester.cpp b/xacc/tests/AlgorithmTester.cpp index e73fe8b37..e2e24e76a 100644 --- a/xacc/tests/AlgorithmTester.cpp +++ b/xacc/tests/AlgorithmTester.cpp @@ -11,6 +11,8 @@ * Alexander J. McCaskey - initial API and implementation *******************************************************************************/ #include +#include +#include #include "xacc.hpp" #include "Algorithm.hpp" @@ -56,6 +58,9 @@ class TestObservable : public Observable { const HeterogeneousMap &extra_data) override { return 0.0; } + std::vector> getMeasurementBasisRotations() override { + return {}; + } }; TEST(AlgorithmTester, checkSimple) { diff --git a/xacc/tests/HeterogeneousTester.cpp b/xacc/tests/HeterogeneousTester.cpp index 8153f7108..8ba2135fe 100644 --- a/xacc/tests/HeterogeneousTester.cpp +++ b/xacc/tests/HeterogeneousTester.cpp @@ -137,6 +137,9 @@ TEST(HeterogeneousMapTester, checkVQE) { const HeterogeneousMap &extra_data) override { return 0.0; } + std::vector> getMeasurementBasisRotations() override { + return {}; + } }; std::shared_ptr observable = std::make_shared(); From 57e3b124717166d14f4807a80b6db15cd419c998 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 20 Jun 2024 17:13:30 +0000 Subject: [PATCH 024/101] Tidying up Signed-off-by: Daniel Claudino --- python/py_observable.cpp | 3 - .../observable/fermion/FermionOperator.hpp | 1 - quantum/observable/pauli/PauliOperator.cpp | 94 ------------------- 3 files changed, 98 deletions(-) diff --git a/python/py_observable.cpp b/python/py_observable.cpp index adab2a32e..982965f85 100644 --- a/python/py_observable.cpp +++ b/python/py_observable.cpp @@ -11,15 +11,12 @@ * Alexander J. McCaskey - initial API and implementation *******************************************************************************/ #include "py_observable.hpp" -//#include "Observable.hpp" #include "Observable.hpp" #include "PauliOperator.hpp" #include "FermionOperator.hpp" -//#include "Utils.hpp" #include "xacc_service.hpp" #include "py_heterogeneous_map.hpp" #include "ObservableTransform.hpp" -//#include using namespace xacc::quantum; diff --git a/quantum/observable/fermion/FermionOperator.hpp b/quantum/observable/fermion/FermionOperator.hpp index c273717a5..2d0265d9e 100644 --- a/quantum/observable/fermion/FermionOperator.hpp +++ b/quantum/observable/fermion/FermionOperator.hpp @@ -195,7 +195,6 @@ class FermionOperator const HeterogeneousMap &extra_data) override; std::shared_ptr normalOrder() override; - std::vector> getMeasurementBasisRotations() override; diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index dea2b9b66..418a5552a 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -238,100 +238,6 @@ PauliOperator::observe(std::shared_ptr function) { return observed; } -/* -std::vector> -PauliOperator::observe(std::shared_ptr function) { - - // Create a new GateQIR to hold the spin based terms - auto gateRegistry = xacc::getService("quantum"); - std::vector> observed; - int counter = 0; - auto pi = xacc::constants::pi; - - // If the incoming function has instructions that have - // their buffer_names set, then we need to set the - // new measurement instructions buffer names to be the same. - // Here we assume that all instructions have the same buffer name - std::string buf_name = ""; - - if (function->nInstructions() > 0 && - !function->getInstruction(0)->getBufferNames().empty()) { - buf_name = function->getInstruction(0)->getBufferNames()[0]; - } - - // Populate GateQIR now... - for (auto &inst : terms) { - - Term spinInst = inst.second; - - auto gateFunction = - gateRegistry->createComposite(inst.first, function->getVariables()); - - gateFunction->setCoefficient(spinInst.coeff()); - - if (function->hasChildren()) { - gateFunction->addInstruction(function->clone()); - } - - for (auto arg : function->getArguments()) { - gateFunction->addArgument(arg, 0); - } - - // Loop over all terms in the Spin Instruction - // and create instructions to run on the Gate QPU. - std::vector> measurements; - auto termsMap = spinInst.ops(); - - std::vector> terms; - for (auto &kv : termsMap) { - if (kv.second != "I" && !kv.second.empty()) { - terms.push_back({kv.first, kv.second}); - } - } - - for (int i = terms.size() - 1; i >= 0; i--) { - auto qbit = terms[i].first; - int t = qbit; - std::size_t tt = t; - auto gateName = terms[i].second; - auto meas = gateRegistry->createInstruction("Measure", - std::vector{tt}); - if (!buf_name.empty()) - meas->setBufferNames({buf_name}); - xacc::InstructionParameter classicalIdx(qbit); - meas->setParameter(0, classicalIdx); - measurements.push_back(meas); - - if (gateName == "X") { - auto hadamard = - gateRegistry->createInstruction("H", std::vector{tt}); - if (!buf_name.empty()) - hadamard->setBufferNames({buf_name}); - gateFunction->addInstruction(hadamard); - } else if (gateName == "Y") { - auto rx = - gateRegistry->createInstruction("Rx", std::vector{tt}); - if (!buf_name.empty()) - rx->setBufferNames({buf_name}); - InstructionParameter p(pi / 2.0); - rx->setParameter(0, p); - gateFunction->addInstruction(rx); - } - } - - if (!spinInst.isIdentity()) { - for (auto m : measurements) { - gateFunction->addInstruction(m); - } - } - - observed.push_back(gateFunction); - counter++; - } - return observed; -} -*/ - std::vector> PauliOperator::observe(std::shared_ptr function, const HeterogeneousMap &grouping_options) { From 582a4a5413767e1571434b09d7fc3fb46127b84a Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:58:14 -0400 Subject: [PATCH 025/101] Update IonQ plugin --- quantum/plugins/ionq/ionq_accelerator.cpp | 11 +++++++---- quantum/plugins/ionq/json/ionq_program.hpp | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/quantum/plugins/ionq/ionq_accelerator.cpp b/quantum/plugins/ionq/ionq_accelerator.cpp index 20726a79f..b2a932658 100644 --- a/quantum/plugins/ionq/ionq_accelerator.cpp +++ b/quantum/plugins/ionq/ionq_accelerator.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace xacc { namespace quantum { @@ -41,9 +43,10 @@ void IonQAccelerator::initialize(const HeterogeneousMap ¶ms) { headers.insert({"Authorization", "apiKey " + apiKey}); headers.insert({"Content-Type", "application/json"}); - auto characterizations = restClient->get(url, "/characterizations/backends/qpu.harmony", headers); + auto characterizations = restClient->get(url, "/jobs", headers); auto j = nlohmann::json::parse(characterizations); - m_connectivity = j["characterizations"][0]["connectivity"].get>>(); + // std::cout << j.dump(1) << std::endl; + // m_connectivity = j["characterizations"][0]["connectivity"].get>>(); remoteUrl = url; postPath = "/jobs"; @@ -145,8 +148,7 @@ void IonQAccelerator::processResponse(std::shared_ptr buffer, std::cout << "\033[0m" << "\n"; auto results = handleExceptionRestClientGet(url, "/jobs/" + jobId + "/results", headers); - - std::map histogram = json::parse(results); + std::map histogram = json::parse(results); int n = buffer->size(); auto getBitStrForInt = [&](std::uint64_t i) { @@ -218,3 +220,4 @@ void IonQAccelerator::findApiKeyInFile(std::string &apiKey, std::string &url, } } // namespace quantum } // namespace xacc + diff --git a/quantum/plugins/ionq/json/ionq_program.hpp b/quantum/plugins/ionq/json/ionq_program.hpp index 7cea6609a..c91014589 100644 --- a/quantum/plugins/ionq/json/ionq_program.hpp +++ b/quantum/plugins/ionq/json/ionq_program.hpp @@ -144,7 +144,7 @@ namespace nlohmann { x.set_lang(j.at("lang").get()); x.set_target(j.at("target").get()); x.set_shots(j.at("shots").get()); - x.set_body(j.at("body").get()); + x.set_body(j.at("input").get()); } inline void to_json(json & j, const xacc::ionq::IonQProgram & x) { @@ -152,6 +152,7 @@ namespace nlohmann { j["lang"] = x.get_lang(); j["target"] = x.get_target(); j["shots"] = x.get_shots(); - j["body"] = x.get_body(); + j["input"] = x.get_body(); } } + From faa66d77dbb5725042edad51ce7aabfb6041dced Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 24 Jun 2024 19:12:41 +0000 Subject: [PATCH 026/101] Updated Accelerator and VQE to work with measurement bases Signed-off-by: Daniel Claudino --- quantum/observable/pauli/PauliOperator.cpp | 6 +- quantum/plugins/algorithms/vqe/vqe.cpp | 152 ++++++++++++------ quantum/plugins/algorithms/vqe/vqe.hpp | 3 +- .../qsim/accelerator/QsimAccelerator.cpp | 51 ++++++ .../qsim/accelerator/QsimAccelerator.hpp | 3 + xacc/accelerator/Accelerator.hpp | 7 + 6 files changed, 166 insertions(+), 56 deletions(-) diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index 418a5552a..198f1d2a7 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -212,7 +212,6 @@ PauliOperator::observe(std::shared_ptr function) { auto it1 = basisRotations.begin(); auto it2 = terms.begin(); for (; it1 != basisRotations.end() && it2 != terms.end(); ++it1, ++it2) { - Term spinInst = (*it2).second; auto gateFunction = @@ -1138,7 +1137,9 @@ std::vector> PauliOperator::getMeasurement terms.push_back({kv.first, kv.second}); } } + auto rotationGates = gateRegistry->createComposite(inst.first); + rotationGates->setCoefficient(spinInst.coeff()); std::vector measureIdxs; for (int i = terms.size() - 1; i >= 0; i--) { @@ -1167,9 +1168,8 @@ std::vector> PauliOperator::getMeasurement meas->setBufferNames({buf_name}); rotationGates->addInstruction(meas); } - basisRotations.push_back(rotationGates); + basisRotations.push_back(rotationGates); } - return basisRotations; } diff --git a/quantum/plugins/algorithms/vqe/vqe.cpp b/quantum/plugins/algorithms/vqe/vqe.cpp index db956878f..e0a1221da 100644 --- a/quantum/plugins/algorithms/vqe/vqe.cpp +++ b/quantum/plugins/algorithms/vqe/vqe.cpp @@ -18,9 +18,7 @@ #include "xacc_service.hpp" #include "AcceleratorDecorator.hpp" -#include #include -#include using namespace xacc; @@ -55,8 +53,6 @@ bool VQE::initialize(const HeterogeneousMap ¶meters) { gradientStrategy = parameters.get>( "gradient_strategy"); - // gradientStrategy->initialize({std::make_pair("observable", - // xacc::as_shared_ptr(observable))}); } if (parameters.stringExists("gradient_strategy") && @@ -82,6 +78,11 @@ bool VQE::initialize(const HeterogeneousMap ¶meters) { gradientStrategy = xacc::getService("autodiff"); gradientStrategy->initialize(parameters); } + + cacheMeasurements = false; + if (parameters.keyExists("cache-measurement-basis")) { + cacheMeasurements = parameters.get("cache-measurement-basis"); + } return true; } @@ -98,11 +99,13 @@ void VQE::execute(const std::shared_ptr buffer) const { std::vector> min_child_buffers; - // auto kernels = observable->observe(xacc::as_shared_ptr(kernel)); // Cache of energy values during iterations. std::vector energies; double last_energy = std::numeric_limits::max(); + if (cacheMeasurements && basisRotations.empty()) + basisRotations = observable->getMeasurementBasisRotations(); + // Here we just need to make a lambda kernel // to optimize that makes calls to the targeted QPU. OptFunction f( @@ -110,35 +113,53 @@ void VQE::execute(const std::shared_ptr buffer) const { std::vector coefficients; std::vector kernelNames; std::vector> fsToExec; + double identityCoeff = 0.0; + int nInstructionsEnergy, nInstructionsGradient = 0; // call CompositeInstruction::operator()() auto evaled = kernel->operator()(x); - // observe - auto kernels = observable->observe(evaled); - double identityCoeff = 0.0; - int nInstructionsEnergy = kernels.size(), nInstructionsGradient = 0; - for (auto &f : kernels) { - kernelNames.push_back(f->name()); - std::complex coeff = f->getCoefficient(); - - int nFunctionInstructions; - if (f->getInstruction(0)->isComposite()) { - nFunctionInstructions = - kernel->nInstructions() + f->nInstructions() - 1; - } else { - nFunctionInstructions = f->nInstructions(); - } + // only deal with the measurement basis instead of entire circuits + if (cacheMeasurements) { - if (nFunctionInstructions > kernel->nInstructions()) { - fsToExec.push_back(f); - coefficients.push_back(std::real(coeff)); - } else { - identityCoeff += std::real(coeff); + nInstructionsEnergy = basisRotations.size() - 1; + for (auto it = basisRotations.begin(); it != basisRotations.end();) { + + kernelNames.push_back((*it)->name()); + std::complex coeff = (*it)->getCoefficient(); + if ((*it)->name() == "I") { + identityCoeff += std::real(coeff); + it = basisRotations.erase(it); + } coefficients.push_back(std::real(coeff)); + ++it; } - } + } else { + + // observe + auto kernels = observable->observe(evaled); + for (auto &f : kernels) { + kernelNames.push_back(f->name()); + std::complex coeff = f->getCoefficient(); + + int nFunctionInstructions; + if (f->getInstruction(0)->isComposite()) { + nFunctionInstructions = + kernel->nInstructions() + f->nInstructions() - 1; + } else { + nFunctionInstructions = f->nInstructions(); + } + + if (nFunctionInstructions > kernel->nInstructions()) { + fsToExec.push_back(f); + coefficients.push_back(std::real(coeff)); + } else { + identityCoeff += std::real(coeff); + coefficients.push_back(std::real(coeff)); + } + } + } // Retrieve instructions for gradient, if a pointer of type // AlgorithmGradientStrategy is given if (gradientStrategy) { @@ -158,7 +179,11 @@ void VQE::execute(const std::shared_ptr buffer) const { } auto tmpBuffer = xacc::qalloc(buffer->size()); - accelerator->execute(tmpBuffer, fsToExec); + if (cacheMeasurements) { + accelerator->execute(tmpBuffer, evaled, basisRotations); + } else { + accelerator->execute(tmpBuffer, fsToExec); + } auto buffers = tmpBuffer->getChildren(); // Tag any gradient buffers; @@ -170,7 +195,6 @@ void VQE::execute(const std::shared_ptr buffer) const { for (auto &[k, v] : tmp_buffer_extra_info) { buffer->addExtraInfo(k, v); } - // Create buffer child for the Identity term auto idBuffer = xacc::qalloc(buffer->size()); idBuffer->addExtraInfo("coefficient", identityCoeff); @@ -181,7 +205,6 @@ void VQE::execute(const std::shared_ptr buffer) const { if (accelerator->name() == "ro-error") idBuffer->addExtraInfo("ro-fixed-exp-val-z", 1.0); buffer->appendChild("I", idBuffer); - // Add information about the variational parameters to the child // buffers. // Other energy (observable-related) information will be populated by @@ -189,7 +212,6 @@ void VQE::execute(const std::shared_ptr buffer) const { for (auto &childBuffer : buffers) { childBuffer->addExtraInfo("parameters", x); } - // Special key to indicate that the buffer was processed by a // HPC virtualization decorator. const std::string aggregate_key = @@ -216,7 +238,6 @@ void VQE::execute(const std::shared_ptr buffer) const { return observable->postProcess(tmpBuffer); } }(); - // Compute the variance as well as populate any variance-related // information to the child buffers const double variance = [&]() { @@ -233,7 +254,6 @@ void VQE::execute(const std::shared_ptr buffer) const { tmpBuffer, Observable::PostProcessingTask::VARIANCE_CALC); } }(); - if (gradientStrategy) { // gradient-based optimization // If gradientStrategy is numerical, pass the energy @@ -257,7 +277,6 @@ void VQE::execute(const std::shared_ptr buffer) const { for (auto &b : buffers) { buffer->appendChild(b->name(), b); } - std::stringstream ss; ss << "E(" << (!x.empty() ? std::to_string(x[0]) : ""); for (int i = 1; i < x.size(); i++) @@ -275,7 +294,6 @@ void VQE::execute(const std::shared_ptr buffer) const { } last_energy = energy; } - return energy; }, kernel->nVariables()); @@ -314,31 +332,61 @@ VQE::execute(const std::shared_ptr buffer, std::vector coefficients; std::vector kernelNames; std::vector> fsToExec; - double identityCoeff = 0.0; - auto evaled = xacc::as_shared_ptr(kernel)->operator()(x); - auto kernels = observable->observe(evaled); - for (auto &f : kernels) { - kernelNames.push_back(f->name()); - std::complex coeff = f->getCoefficient(); - - int nFunctionInstructions = 0; - if (f->getInstruction(0)->isComposite()) { - nFunctionInstructions = kernel->nInstructions() + f->nInstructions() - 1; - } else { - nFunctionInstructions = f->nInstructions(); - } + int nInstructionsEnergy, nInstructionsGradient = 0; - if (nFunctionInstructions > kernel->nInstructions()) { - fsToExec.push_back(f); + // call CompositeInstruction::operator()() + auto evaled = kernel->operator()(x); + + // if we want to only deal with the measurement basis instead of entire + // circuits + if (cacheMeasurements) { + + nInstructionsEnergy = basisRotations.size() - 1; + for (auto it = basisRotations.begin(); it != basisRotations.end();) { + + kernelNames.push_back((*it)->name()); + std::complex coeff = (*it)->getCoefficient(); + if ((*it)->name() == "I") { + identityCoeff += std::real(coeff); + it = basisRotations.erase(it); + } coefficients.push_back(std::real(coeff)); - } else { - identityCoeff += std::real(coeff); + ++it; + } + + } else { + + // observe + auto kernels = observable->observe(evaled); + for (auto &f : kernels) { + kernelNames.push_back(f->name()); + std::complex coeff = f->getCoefficient(); + + int nFunctionInstructions; + if (f->getInstruction(0)->isComposite()) { + nFunctionInstructions = + kernel->nInstructions() + f->nInstructions() - 1; + } else { + nFunctionInstructions = f->nInstructions(); + } + + if (nFunctionInstructions > kernel->nInstructions()) { + fsToExec.push_back(f); + coefficients.push_back(std::real(coeff)); + } else { + identityCoeff += std::real(coeff); + coefficients.push_back(std::real(coeff)); + } } } auto tmpBuffer = xacc::qalloc(buffer->size()); - accelerator->execute(tmpBuffer, fsToExec); + if (cacheMeasurements) { + accelerator->execute(tmpBuffer, evaled, basisRotations); + } else { + accelerator->execute(tmpBuffer, fsToExec); + } auto buffers = tmpBuffer->getChildren(); for (auto &b : buffers) { b->addExtraInfo("parameters", x); diff --git a/quantum/plugins/algorithms/vqe/vqe.hpp b/quantum/plugins/algorithms/vqe/vqe.hpp index 13bce642c..01350f6ef 100644 --- a/quantum/plugins/algorithms/vqe/vqe.hpp +++ b/quantum/plugins/algorithms/vqe/vqe.hpp @@ -26,7 +26,8 @@ class VQE : public Algorithm { Accelerator * accelerator; std::vector initial_params; std::shared_ptr gradientStrategy; - + mutable std::vector> basisRotations; + bool cacheMeasurements; HeterogeneousMap parameters; public: diff --git a/quantum/plugins/qsim/accelerator/QsimAccelerator.cpp b/quantum/plugins/qsim/accelerator/QsimAccelerator.cpp index 52701d9df..98120e524 100644 --- a/quantum/plugins/qsim/accelerator/QsimAccelerator.cpp +++ b/quantum/plugins/qsim/accelerator/QsimAccelerator.cpp @@ -11,6 +11,7 @@ * Thien Nguyen - initial API and implementation *******************************************************************************/ #include "QsimAccelerator.hpp" +#include "xacc.hpp" #include "xacc_plugin.hpp" #include "IRUtils.hpp" #include @@ -274,6 +275,56 @@ void QsimAccelerator::execute( } } +void QsimAccelerator::execute(std::shared_ptr buffer, + const std::shared_ptr baseCircuit, + const std::vector> basisRotations) { + + constexpr int MAX_NUMBER_CIRCUITS_TO_ANALYZE = 100; + if (!m_vqeMode || basisRotations.size() <= 1 || + basisRotations.size() > MAX_NUMBER_CIRCUITS_TO_ANALYZE) { + auto provider = getIRProvider("quantum"); + // Cannot run VQE mode, just run each composite independently. + for (auto &b : basisRotations) { + auto f = provider->createComposite(b->name(), baseCircuit->getVariables()); + auto tmpBuffer = + std::make_shared(b->name(), buffer->size()); + execute(tmpBuffer, f); + buffer->appendChild(f->name(), tmpBuffer); + } + } else { + xacc::info("Running VQE mode"); + QsimCircuitVisitor visitor(buffer->size()); + // Walk the base IR tree, and visit each node + InstructionIterator it(baseCircuit); + while (it.hasNext()) { + auto nextInst = it.next(); + if (nextInst->isEnabled() && !nextInst->isComposite()) { + nextInst->accept(&visitor); + } + } + + // Run the base circuit: + auto circuit = visitor.getQsimCircuit(); + StateSpace stateSpace(m_numThreads); + State state = stateSpace.Create(circuit.num_qubits); + stateSpace.SetStateZero(state); + + const bool runOk = Runner::Run(m_qsimParam, Factory(m_numThreads), circuit, state); + assert(runOk); + + // Now we have a wavefunction that represents execution of the ansatz. + // Run the observable sub-circuits (change of basis + measurements) + for (int i = 0; i < basisRotations.size(); ++i) { + auto tmpBuffer = std::make_shared( + basisRotations[i]->name(), buffer->size()); + const double e = getExpectationValueZ(basisRotations[i], stateSpace, state); + tmpBuffer->addExtraInfo("exp-val-z", e); + buffer->appendChild(basisRotations[i]->name(), tmpBuffer); + } + } + +} + double QsimAccelerator::getExpectationValueZ( std::shared_ptr compositeInstruction, const StateSpace &stateSpace, const State &state) const { diff --git a/quantum/plugins/qsim/accelerator/QsimAccelerator.hpp b/quantum/plugins/qsim/accelerator/QsimAccelerator.hpp index db31a5090..70d0998f0 100644 --- a/quantum/plugins/qsim/accelerator/QsimAccelerator.hpp +++ b/quantum/plugins/qsim/accelerator/QsimAccelerator.hpp @@ -319,6 +319,9 @@ class QsimAccelerator : public Accelerator { virtual void execute(std::shared_ptr buffer, const std::vector> compositeInstructions) override; + void execute(std::shared_ptr buffer, + const std::shared_ptr baseCircuit, + const std::vector> basisRotations) override; virtual void apply(std::shared_ptr buffer, std::shared_ptr inst) override; diff --git a/xacc/accelerator/Accelerator.hpp b/xacc/accelerator/Accelerator.hpp index 2e672db01..4fc5c1802 100644 --- a/xacc/accelerator/Accelerator.hpp +++ b/xacc/accelerator/Accelerator.hpp @@ -100,6 +100,13 @@ class Accelerator : public Identifiable { const std::vector> CompositeInstructions) = 0; + virtual void + execute(std::shared_ptr buffer, + const std::shared_ptr baseCircuit, + const std::vector> basisRotations) { + return; + } + virtual void cancel(){}; virtual std::vector> getConnectivity() { From 702cfcef93bfd9b1f85a2df20722cbedcd39f1c3 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 24 Jun 2024 20:28:36 +0000 Subject: [PATCH 027/101] Reverting C++ Micro Services Signed-off-by: Daniel Claudino --- .gitmodules | 2 +- tpls/cppmicroservices | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index eebd43b46..ef75a52d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,7 @@ url = https://github.com/ornl-qci/boost-cmake [submodule "tpls/cppmicroservices"] path = tpls/cppmicroservices - url = https://github.com/CppMicroServices/CppMicroServices + url = https://github.com/ORNL-QCI/CppMicroServices.git [submodule "quantum/plugins/dwave/embedding/minorminer"] path = quantum/plugins/dwave/embedding/minorminer url = https://github.com/dwavesystems/minorminer diff --git a/tpls/cppmicroservices b/tpls/cppmicroservices index 899530e5b..3dfb92faa 160000 --- a/tpls/cppmicroservices +++ b/tpls/cppmicroservices @@ -1 +1 @@ -Subproject commit 899530e5b6929c90479b1b6040d2a530776fc8a4 +Subproject commit 3dfb92faa2bd8e281d2ca85acccdf7eb93b9a442 From b240b764e7e31838749de8addce011575a06d01a Mon Sep 17 00:00:00 2001 From: wongey <25296194+wongey@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:52:24 -0400 Subject: [PATCH 028/101] Update IonQ Tester --- quantum/plugins/ionq/tests/IonQProgramTester.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/ionq/tests/IonQProgramTester.cpp b/quantum/plugins/ionq/tests/IonQProgramTester.cpp index ef9079e94..10f2e7f95 100644 --- a/quantum/plugins/ionq/tests/IonQProgramTester.cpp +++ b/quantum/plugins/ionq/tests/IonQProgramTester.cpp @@ -20,7 +20,7 @@ TEST(IonQProgramTester, checkFromJson) { "lang": "json", "target": "qpu", "shots": 1000, - "body": { + "input": { "qubits": 2, "circuit": [ { From 9441a265c506a07713b9c94c468e71f31fc71688 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 25 Jun 2024 09:50:15 -0400 Subject: [PATCH 029/101] Update ci-linux-python.yml The new numpy 2.0 is incompatible with cma, so for now we constrain the numpy version. --- .github/workflows/ci-linux-python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-linux-python.yml b/.github/workflows/ci-linux-python.yml index 97cadf3a3..f48f72adf 100644 --- a/.github/workflows/ci-linux-python.yml +++ b/.github/workflows/ci-linux-python.yml @@ -28,7 +28,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get install -y --no-install-recommends ninja-build libssl-dev libcurl4-openssl-dev python3 libpython3-dev python3-pip libblas-dev liblapack-dev - name: Install optional Python Packages - run: python3 -m pip install numpy pyscf cma + run: python3 -m pip install numpy<=1.26.4 pyscf cma - name: Configure working-directory: build/ @@ -40,4 +40,4 @@ jobs: - name: Test working-directory: python/tests - run: export PYTHONPATH=$PYTHONPATH:~/.xacc && python3 -m unittest discover -s . -p '*_testing.py' \ No newline at end of file + run: export PYTHONPATH=$PYTHONPATH:~/.xacc && python3 -m unittest discover -s . -p '*_testing.py' From fef5458c5ae2e9b698a652d7345741ffd7945ae5 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 25 Jun 2024 09:56:27 -0400 Subject: [PATCH 030/101] Update ci-linux-python.yml --- .github/workflows/ci-linux-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-linux-python.yml b/.github/workflows/ci-linux-python.yml index f48f72adf..b2b6b9d2d 100644 --- a/.github/workflows/ci-linux-python.yml +++ b/.github/workflows/ci-linux-python.yml @@ -28,7 +28,7 @@ jobs: run: sudo apt-get -y update && sudo apt-get install -y --no-install-recommends ninja-build libssl-dev libcurl4-openssl-dev python3 libpython3-dev python3-pip libblas-dev liblapack-dev - name: Install optional Python Packages - run: python3 -m pip install numpy<=1.26.4 pyscf cma + run: python3 -m pip install "numpy<=1.26.4" pyscf cma - name: Configure working-directory: build/ From cc699952659e2b8eb422bb06c6b67178a9e0cd31 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Wed, 26 Jun 2024 19:25:59 +0000 Subject: [PATCH 031/101] Implemented Scipy optimizer plugin Signed-off-by: Daniel Claudino --- quantum/plugins/optimizers/CMakeLists.txt | 3 +- .../plugins/optimizers/scipy/CMakeLists.txt | 58 +++++++ .../plugins/optimizers/scipy/manifest.json | 6 + .../optimizers/scipy/scipy_optimizer.cpp | 162 ++++++++++++++++++ .../optimizers/scipy/scipy_optimizer.hpp | 26 +++ .../optimizers/scipy/tests/CMakeLists.txt | 4 + .../scipy/tests/ScipyOptimizerTester.cpp | 103 +++++++++++ 7 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 quantum/plugins/optimizers/scipy/CMakeLists.txt create mode 100644 quantum/plugins/optimizers/scipy/manifest.json create mode 100644 quantum/plugins/optimizers/scipy/scipy_optimizer.cpp create mode 100644 quantum/plugins/optimizers/scipy/scipy_optimizer.hpp create mode 100644 quantum/plugins/optimizers/scipy/tests/CMakeLists.txt create mode 100644 quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp diff --git a/quantum/plugins/optimizers/CMakeLists.txt b/quantum/plugins/optimizers/CMakeLists.txt index d764e5c20..2d8be5138 100644 --- a/quantum/plugins/optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(nlopt-optimizers) -add_subdirectory(mlpack) \ No newline at end of file +add_subdirectory(mlpack) +add_subdirectory(scipy) \ No newline at end of file diff --git a/quantum/plugins/optimizers/scipy/CMakeLists.txt b/quantum/plugins/optimizers/scipy/CMakeLists.txt new file mode 100644 index 000000000..cb5b7a298 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/CMakeLists.txt @@ -0,0 +1,58 @@ +message(STATUS "${BoldGreen}Building Scipy Optimizer.${ColorReset}") +set(LIBRARY_NAME xacc-scipy-optimizer) + +file(GLOB + SRC + scipy_optimizer.cpp) + +usfunctiongetresourcesource(TARGET + ${LIBRARY_NAME} + OUT + SRC) +usfunctiongeneratebundleinit(TARGET + ${LIBRARY_NAME} + OUT + SRC) +#find_package(pybind11 REQUIRED) +find_package(Python COMPONENTS Interpreter Development) + +add_library(${LIBRARY_NAME} SHARED ${SRC}) + +if(Python_FOUND) + message("FOUND python") +endif() +target_include_directories(${LIBRARY_NAME} + PUBLIC . ${CMAKE_SOURCE_DIR}/tpls/pybind11/include ${Python_INCLUDE_DIRS}) + + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc Python::Python) + +set(_bundle_name xacc_optimizer_scipy) +set_target_properties(${LIBRARY_NAME} + PROPERTIES COMPILE_DEFINITIONS + US_BUNDLE_NAME=${_bundle_name} + US_BUNDLE_NAME + ${_bundle_name}) + +usfunctionembedresources(TARGET + ${LIBRARY_NAME} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + FILES + manifest.json) + +if(APPLE) + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "@loader_path/../lib") + set_target_properties(${LIBRARY_NAME} + PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +else() + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") + set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") +endif() + +if(XACC_BUILD_TESTS) + add_subdirectory(tests) +endif() + +install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) diff --git a/quantum/plugins/optimizers/scipy/manifest.json b/quantum/plugins/optimizers/scipy/manifest.json new file mode 100644 index 000000000..e91935fa7 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/manifest.json @@ -0,0 +1,6 @@ +{ + "bundle.symbolic_name" : "xacc_optimizer_scipy", + "bundle.activator" : true, + "bundle.name" : "XACC Scipy Optimizer", + "bundle.description" : "" +} diff --git a/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp new file mode 100644 index 000000000..7c617388d --- /dev/null +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp @@ -0,0 +1,162 @@ +#include "scipy_optimizer.hpp" +#include "Optimizer.hpp" +#include "pybind11/stl.h" +#include "pybind11/numpy.h" +#include "xacc.hpp" +#include "xacc_plugin.hpp" + +namespace py = pybind11; + +namespace xacc { + +const std::string ScipyOptimizer::get_algorithm() const { + std::string optimizerAlgo = "COBYLA"; + if (options.stringExists("algorithm")) { + optimizerAlgo = options.getString("algorithm"); + } + if (options.stringExists("scipy-optimizer")) { + optimizerAlgo = options.getString("scipy-optimizer"); + } + return optimizerAlgo; +} + +const bool ScipyOptimizer::isGradientBased() const { + + std::string optimizerAlgo = "cobyla"; + if (options.stringExists("algorithm")) { + optimizerAlgo = options.getString("algorithm"); + } + if (options.stringExists("scipy-optimizer")) { + optimizerAlgo = options.getString("scipy-optimizer"); + } + + if (options.stringExists("optimizer")) { + optimizerAlgo = options.getString("optimizer"); + } + + if (optimizerAlgo == "bfgs") { + return true; + } else { + return false; + } +} + +OptResult ScipyOptimizer::optimize(OptFunction& function) { + + bool maximize = false; + if (options.keyExists("maximize")) { + xacc::info("Turning on maximize!"); + maximize = options.get("maximize"); + } + + std::string algo = "COBYLA"; + if (options.stringExists("algorithm")) { + algo = options.getString("algorithm"); + } + if (options.stringExists("scipy-optimizer")) { + algo = options.getString("scipy-optimizer"); + } + if (options.stringExists("optimizer")) { + algo = options.getString("optimizer"); + } + + if (algo == "cobyla" || algo == "COBYLA") { + algo ="COBYLA"; + } else if (algo == "nelder-mead" || algo == "Nelder-Mead") { + algo = "Nelder-Mead"; + } else if (algo == "bfgs" || algo == "BFGS" || algo == "l-bfgs") { + algo = "BFGS"; + } else { + xacc::XACCLogger::instance()->error("Invalid optimizer at this time: " + + algo); + } + + double tol = 1e-6; + if (options.keyExists("ftol")) { + tol = options.get("ftol"); + xacc::info("[Scipy] function tolerance set to " + std::to_string(tol)); + } + if (options.keyExists("scipy-ftol")) { + tol = options.get("ftol"); + xacc::info("[Scipy] function tolerance set to " + std::to_string(tol)); + } + + int maxeval = 1000; + if (options.keyExists("maxeval")) { + maxeval = options.get("maxeval"); + xacc::info("[Scipy] max function evaluations set to " + + std::to_string(maxeval)); + } + if (options.keyExists("scipy-maxeval")) { + maxeval = options.get("maxeval"); + xacc::info("[Scipy] max function evaluations set to " + + std::to_string(maxeval)); + } + + std::vector x(function.dimensions()); + if (options.keyExists>("initial-parameters")) { + x = options.get_with_throw>("initial-parameters"); + } else if (options.keyExists>("initial-parameters")) { + auto tmpx = options.get>("initial-parameters"); + x = std::vector(tmpx.begin(), tmpx.end()); + } + + // here the python stuff starts + py::list pyInitialParams; + for (const auto ¶m : x) { + pyInitialParams.append(param); + } + + if (isGradientBased()) std::cout << algo << "\n"; + + // wrap the objective function in this lambda + // scipy passes a numpy array to this function, hence the py::array_t type + py::object pyObjFunction = py::cpp_function([&function](const py::array_t& pyParams) { + std::vector params(pyParams.size()); + std::memcpy(params.data(), pyParams.data(), pyParams.size() * sizeof(double)); + return function(std::move(params)); + }); + + // call this for gradient-based optimization + py::object pyObjFunctionWithGrad = py::cpp_function([&function](const py::array_t& pyParams) { + std::vector params(pyParams.size()); + std::memcpy(params.data(), pyParams.data(), pyParams.size() * sizeof(double)); + + std::vector grad(params.size()); + double result = function(params, grad); + py::array_t pyGrad(grad.size()); + std::memcpy(pyGrad.mutable_data(), grad.data(), grad.size() * sizeof(double)); + + return py::make_tuple(result, pyGrad); + }); + + py::module scipy_optimize = py::module::import("scipy.optimize"); + + // error handling helps here to see if it's coming from C++ or python + try { + + py::object result = scipy_optimize.attr("minimize")( + isGradientBased() ? pyObjFunctionWithGrad : pyObjFunction, + pyInitialParams, + py::arg("args") = py::tuple(), + py::arg("method") = algo, + py::arg("tol") = tol, + py::arg("jac") = (isGradientBased() ? true : false) + ); + + std::vector optimizedParams = result.attr("x").cast>(); + double optimalValue = result.attr("fun").cast(); + + return {optimalValue, optimizedParams}; + } catch (const py::error_already_set& e) { + std::cerr << "Python error: " << e.what() << std::endl; + throw; + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + throw; + } +} +} // namespace xacc + +// Register the plugin with XACC +REGISTER_OPTIMIZER(xacc::ScipyOptimizer) \ No newline at end of file diff --git a/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp b/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp new file mode 100644 index 000000000..49b3e50ab --- /dev/null +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp @@ -0,0 +1,26 @@ +#ifndef SCIPYOPTIMIZER_HPP +#define SCIPYOPTIMIZER_HPP + +#include +#include +#include +#include + +namespace xacc { + +class ScipyOptimizer : public xacc::Optimizer { +public: + + ScipyOptimizer() = default; + ~ScipyOptimizer() = default; + + const std::string name() const override { return "scipy"; } + const std::string description() const override { return ""; } + + OptResult optimize(OptFunction &function) override; + const bool isGradientBased() const override; + virtual const std::string get_algorithm() const override; +}; + +} // namespace xacc +#endif // SCIPYOPTIMIZER_HPP diff --git a/quantum/plugins/optimizers/scipy/tests/CMakeLists.txt b/quantum/plugins/optimizers/scipy/tests/CMakeLists.txt new file mode 100644 index 000000000..37a7aec7e --- /dev/null +++ b/quantum/plugins/optimizers/scipy/tests/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(${CMAKE_SOURCE_DIR}/tpls/pybind11/include ${Python_INCLUDE_DIRS}) + +add_xacc_test(ScipyOptimizer) +target_link_libraries(ScipyOptimizerTester xacc Python::Python) \ No newline at end of file diff --git a/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp b/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp new file mode 100644 index 000000000..f2e3c6315 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp @@ -0,0 +1,103 @@ +#include +#include "xacc.hpp" +#include "xacc_service.hpp" +#include +#include + +using namespace xacc; +namespace py = pybind11; + +TEST(ScipyOptimizerTester, checkSimple) { + + + auto optimizer = + xacc::getService("scipy"); // NLOptimizer optimizer; + + OptFunction f([](const std::vector &x, std::vector& g) { return x[0] * x[0] + 5; }, + 1); + + EXPECT_EQ(optimizer->name(), "scipy"); + EXPECT_EQ(1, f.dimensions()); + + + optimizer->setOptions(HeterogeneousMap{std::make_pair("maxeval", 20)}); + + auto result = optimizer->optimize(f); + EXPECT_NEAR(5.0, result.first, 1.0e-6); + EXPECT_NEAR(result.second[0], 0.0, 1.0e-6); + +} + +TEST(ScipyOptimizerTester, checkGradient) { + + auto optimizer = + xacc::getService("scipy"); + + OptFunction f( + [](const std::vector &x, std::vector &grad) { + if (!grad.empty()) { + std::cout << "GRAD\n"; + grad[0] = 2. * x[0]; + } + auto xx = x[0] * x[0] + 5; + std::cout << xx << "\n"; + return xx; + }, + 1); + + EXPECT_EQ(1, f.dimensions()); + + + optimizer->setOptions( + HeterogeneousMap{std::make_pair("maxeval", 20),std::make_pair("initial-parameters", std::vector{1.0}), + std::make_pair("optimizer", "bfgs")}); + + auto result = optimizer->optimize(f); + + EXPECT_NEAR(result.first, 5.0, 1e-4); + EXPECT_NEAR(result.second[0], 0.0, 1e-4); +} + +TEST(ScipyOptimizerTester, checkGradientRosenbrock) { + + auto optimizer = + xacc::getService("scipy"); + + OptFunction f( + [](const std::vector &x, std::vector &grad) { + if (!grad.empty()) { + // std::cout << "GRAD\n"; + grad[0] = -2 * (1 - x[0]) + 400 * (std::pow(x[0], 3) - x[1] * x[0]); + grad[1] = 200 * (x[1] - std::pow(x[0],2)); + } + auto xx = 100 * std::pow(x[1] - std::pow(x[0], 2), 2) + std::pow(1 - x[0], 2); + std::cout << xx << ", " << x << ", " << grad << "\n"; + + return xx; + }, + 2); + + EXPECT_EQ(2, f.dimensions()); + + optimizer->setOptions( + HeterogeneousMap{std::make_pair("maxeval", 200), + std::make_pair("optimizer", "bfgs")}); + + auto result = optimizer->optimize(f); + + EXPECT_NEAR(result.first, 0.0, 1e-4); + EXPECT_NEAR(result.second[0], 1.0, 1e-4); + EXPECT_NEAR(result.second[1], 1.0, 1e-4); + +} + +int main(int argc, char **argv) { + dlopen("libpython3.8.so", RTLD_LAZY | RTLD_GLOBAL); + xacc::Initialize(argc, argv); + py::initialize_interpreter(); + ::testing::InitGoogleTest(&argc, argv); + auto ret = RUN_ALL_TESTS(); + py::finalize_interpreter(); + xacc::Finalize(); + return ret; +} From 8054735ad2609f785b6d5469e0bbba55a1948c88 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 27 Jun 2024 10:18:20 +0000 Subject: [PATCH 032/101] Tidying up scipy optimizer Signed-off-by: Daniel Claudino --- CMakeLists.txt | 1 + quantum/plugins/optimizers/CMakeLists.txt | 22 ++++- .../plugins/optimizers/scipy/CMakeLists.txt | 3 - .../optimizers/scipy/scipy_optimizer.cpp | 87 ++++++++++--------- .../optimizers/scipy/scipy_optimizer.hpp | 1 - .../scipy/tests/ScipyOptimizerTester.cpp | 39 ++++----- 6 files changed, 84 insertions(+), 69 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b65babcc..15452f92d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ option(XACC_BUILD_EXAMPLES "Build example programs" OFF) option(XACC_ENSMALLEN_INCLUDE_DIR "Path to ensmallen.hpp for mlpack optimizer" "") option(XACC_ARMADILLO_INCLUDE_DIR "Path to armadillo header for mlpack optimizer" "") option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) +option(XACC_BUILD_SCIPY "Build Scipy optimizer plugin" OFF) if(XACC_BUILD_ANNEALING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") else() diff --git a/quantum/plugins/optimizers/CMakeLists.txt b/quantum/plugins/optimizers/CMakeLists.txt index 2d8be5138..bcfcf75ec 100644 --- a/quantum/plugins/optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/CMakeLists.txt @@ -1,3 +1,23 @@ add_subdirectory(nlopt-optimizers) add_subdirectory(mlpack) -add_subdirectory(scipy) \ No newline at end of file +if(XACC_BUILD_SCIPY) + execute_process(COMMAND ${Python_EXECUTABLE} -c "import scipy" RESULT_VARIABLE SCIPY_EXISTS) + if(SCIPY_EXISTS EQUAL "1") + # if not, check we have pip + execute_process(COMMAND ${Python_EXECUTABLE} -c "import pip" RESULT_VARIABLE PIP_EXISTS) + + if(PIP_EXISTS EQUAL "0") + # we have pip, so just install scipy + message(STATUS "${BoldGreen}Installing Scipy.${ColorReset}") + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install scipy) + else() + # we dont have pip, so warn the user + message(STATUS "${BoldYellow}Scipy not found, but can't install via pip. Ensure you install scipy module if you would like to use the Scipy optimizer.${ColorReset}") + endif() +else() + message(STATUS "${BoldGreen}Found Scipy.${ColorReset}") +endif() + add_subdirectory(scipy) +else() + message(STATUS "${BoldYellow}XACC will not build the Scipy optimizer. You can turn it on with -DXACC_BUILD_SCIPY=ON${ColorReset}") +endif() \ No newline at end of file diff --git a/quantum/plugins/optimizers/scipy/CMakeLists.txt b/quantum/plugins/optimizers/scipy/CMakeLists.txt index cb5b7a298..119ecf551 100644 --- a/quantum/plugins/optimizers/scipy/CMakeLists.txt +++ b/quantum/plugins/optimizers/scipy/CMakeLists.txt @@ -18,9 +18,6 @@ find_package(Python COMPONENTS Interpreter Development) add_library(${LIBRARY_NAME} SHARED ${SRC}) -if(Python_FOUND) - message("FOUND python") -endif() target_include_directories(${LIBRARY_NAME} PUBLIC . ${CMAKE_SOURCE_DIR}/tpls/pybind11/include ${Python_INCLUDE_DIRS}) diff --git a/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp index 7c617388d..38e4760fe 100644 --- a/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp @@ -41,11 +41,11 @@ const bool ScipyOptimizer::isGradientBased() const { } } -OptResult ScipyOptimizer::optimize(OptFunction& function) { - +OptResult ScipyOptimizer::optimize(OptFunction &function) { + bool maximize = false; if (options.keyExists("maximize")) { - xacc::info("Turning on maximize!"); + xacc::info("Turning on maximize!"); maximize = options.get("maximize"); } @@ -60,16 +60,16 @@ OptResult ScipyOptimizer::optimize(OptFunction& function) { algo = options.getString("optimizer"); } - if (algo == "cobyla" || algo == "COBYLA") { - algo ="COBYLA"; - } else if (algo == "nelder-mead" || algo == "Nelder-Mead") { - algo = "Nelder-Mead"; - } else if (algo == "bfgs" || algo == "BFGS" || algo == "l-bfgs") { - algo = "BFGS"; - } else { - xacc::XACCLogger::instance()->error("Invalid optimizer at this time: " + - algo); - } + if (algo == "cobyla" || algo == "COBYLA") { + algo = "COBYLA"; + } else if (algo == "nelder-mead" || algo == "Nelder-Mead") { + algo = "Nelder-Mead"; + } else if (algo == "bfgs" || algo == "BFGS" || algo == "l-bfgs") { + algo = "BFGS"; + } else { + xacc::XACCLogger::instance()->error("Invalid optimizer at this time: " + + algo); + } double tol = 1e-6; if (options.keyExists("ftol")) { @@ -104,31 +104,34 @@ OptResult ScipyOptimizer::optimize(OptFunction& function) { // here the python stuff starts py::list pyInitialParams; for (const auto ¶m : x) { - pyInitialParams.append(param); + pyInitialParams.append(param); } - if (isGradientBased()) std::cout << algo << "\n"; - // wrap the objective function in this lambda // scipy passes a numpy array to this function, hence the py::array_t type - py::object pyObjFunction = py::cpp_function([&function](const py::array_t& pyParams) { - std::vector params(pyParams.size()); - std::memcpy(params.data(), pyParams.data(), pyParams.size() * sizeof(double)); - return function(std::move(params)); - }); + py::object pyObjFunction = + py::cpp_function([&function](const py::array_t &pyParams) { + std::vector params(pyParams.size()); + std::memcpy(params.data(), pyParams.data(), + pyParams.size() * sizeof(double)); + return function(std::move(params)); + }); // call this for gradient-based optimization - py::object pyObjFunctionWithGrad = py::cpp_function([&function](const py::array_t& pyParams) { - std::vector params(pyParams.size()); - std::memcpy(params.data(), pyParams.data(), pyParams.size() * sizeof(double)); - - std::vector grad(params.size()); - double result = function(params, grad); - py::array_t pyGrad(grad.size()); - std::memcpy(pyGrad.mutable_data(), grad.data(), grad.size() * sizeof(double)); - - return py::make_tuple(result, pyGrad); - }); + py::object pyObjFunctionWithGrad = + py::cpp_function([&function](const py::array_t &pyParams) { + std::vector params(pyParams.size()); + std::memcpy(params.data(), pyParams.data(), + pyParams.size() * sizeof(double)); + + std::vector grad(params.size()); + double result = function(params, grad); + py::array_t pyGrad(grad.size()); + std::memcpy(pyGrad.mutable_data(), grad.data(), + grad.size() * sizeof(double)); + + return py::make_tuple(result, pyGrad); + }); py::module scipy_optimize = py::module::import("scipy.optimize"); @@ -141,20 +144,20 @@ OptResult ScipyOptimizer::optimize(OptFunction& function) { py::arg("args") = py::tuple(), py::arg("method") = algo, py::arg("tol") = tol, - py::arg("jac") = (isGradientBased() ? true : false) - ); + py::arg("jac") = (isGradientBased() ? true : false)); - std::vector optimizedParams = result.attr("x").cast>(); + std::vector optimizedParams = + result.attr("x").cast>(); double optimalValue = result.attr("fun").cast(); return {optimalValue, optimizedParams}; - } catch (const py::error_already_set& e) { - std::cerr << "Python error: " << e.what() << std::endl; - throw; - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - throw; - } + } catch (const py::error_already_set &e) { + std::cerr << "Python error: " << e.what() << std::endl; + throw; + } catch (const std::exception &e) { + std::cerr << "Error: " << e.what() << std::endl; + throw; + } } } // namespace xacc diff --git a/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp b/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp index 49b3e50ab..25235c3b6 100644 --- a/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp @@ -10,7 +10,6 @@ namespace xacc { class ScipyOptimizer : public xacc::Optimizer { public: - ScipyOptimizer() = default; ~ScipyOptimizer() = default; diff --git a/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp b/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp index f2e3c6315..8b3424303 100644 --- a/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp +++ b/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp @@ -9,29 +9,26 @@ namespace py = pybind11; TEST(ScipyOptimizerTester, checkSimple) { - auto optimizer = - xacc::getService("scipy"); // NLOptimizer optimizer; + xacc::getService("scipy"); - OptFunction f([](const std::vector &x, std::vector& g) { return x[0] * x[0] + 5; }, + OptFunction f([](const std::vector &x, + std::vector &g) { return x[0] * x[0] + 5; }, 1); EXPECT_EQ(optimizer->name(), "scipy"); EXPECT_EQ(1, f.dimensions()); - optimizer->setOptions(HeterogeneousMap{std::make_pair("maxeval", 20)}); - + auto result = optimizer->optimize(f); EXPECT_NEAR(5.0, result.first, 1.0e-6); EXPECT_NEAR(result.second[0], 0.0, 1.0e-6); - } TEST(ScipyOptimizerTester, checkGradient) { - auto optimizer = - xacc::getService("scipy"); + auto optimizer = xacc::getService("scipy"); OptFunction f( [](const std::vector &x, std::vector &grad) { @@ -47,10 +44,10 @@ TEST(ScipyOptimizerTester, checkGradient) { EXPECT_EQ(1, f.dimensions()); - - optimizer->setOptions( - HeterogeneousMap{std::make_pair("maxeval", 20),std::make_pair("initial-parameters", std::vector{1.0}), - std::make_pair("optimizer", "bfgs")}); + optimizer->setOptions(HeterogeneousMap{ + std::make_pair("maxeval", 20), + std::make_pair("initial-parameters", std::vector{1.0}), + std::make_pair("optimizer", "bfgs")}); auto result = optimizer->optimize(f); @@ -60,35 +57,33 @@ TEST(ScipyOptimizerTester, checkGradient) { TEST(ScipyOptimizerTester, checkGradientRosenbrock) { - auto optimizer = - xacc::getService("scipy"); + auto optimizer = xacc::getService("scipy"); OptFunction f( [](const std::vector &x, std::vector &grad) { if (!grad.empty()) { - // std::cout << "GRAD\n"; + // std::cout << "GRAD\n"; grad[0] = -2 * (1 - x[0]) + 400 * (std::pow(x[0], 3) - x[1] * x[0]); - grad[1] = 200 * (x[1] - std::pow(x[0],2)); + grad[1] = 200 * (x[1] - std::pow(x[0], 2)); } - auto xx = 100 * std::pow(x[1] - std::pow(x[0], 2), 2) + std::pow(1 - x[0], 2); + auto xx = + 100 * std::pow(x[1] - std::pow(x[0], 2), 2) + std::pow(1 - x[0], 2); std::cout << xx << ", " << x << ", " << grad << "\n"; - + return xx; }, 2); EXPECT_EQ(2, f.dimensions()); - optimizer->setOptions( - HeterogeneousMap{std::make_pair("maxeval", 200), - std::make_pair("optimizer", "bfgs")}); + optimizer->setOptions(HeterogeneousMap{std::make_pair("maxeval", 200), + std::make_pair("optimizer", "bfgs")}); auto result = optimizer->optimize(f); EXPECT_NEAR(result.first, 0.0, 1e-4); EXPECT_NEAR(result.second[0], 1.0, 1e-4); EXPECT_NEAR(result.second[1], 1.0, 1e-4); - } int main(int argc, char **argv) { From 84eab52824aff537b6c1321e8e6973e34d5e8d1d Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 2 Jul 2024 18:38:14 +0000 Subject: [PATCH 033/101] Updated tpls/cppmicroservices to include recent updates Signed-off-by: Daniel Claudino --- tpls/cppmicroservices | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/cppmicroservices b/tpls/cppmicroservices index 3dfb92faa..8570c9e65 160000 --- a/tpls/cppmicroservices +++ b/tpls/cppmicroservices @@ -1 +1 @@ -Subproject commit 3dfb92faa2bd8e281d2ca85acccdf7eb93b9a442 +Subproject commit 8570c9e65296c146c2446f385f9aa741e18af0d6 From 86c4d3c028c5c7e05f7cf0a27768f464dda39514 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Wed, 3 Jul 2024 13:43:40 +0000 Subject: [PATCH 034/101] Updated boost/regex Signed-off-by: Daniel Claudino --- tpls/boost-cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/boost-cmake b/tpls/boost-cmake index be32761fb..05fabb4d4 160000 --- a/tpls/boost-cmake +++ b/tpls/boost-cmake @@ -1 +1 @@ -Subproject commit be32761fb35199ef712f285697e9146c75559608 +Subproject commit 05fabb4d416496bc19a84e82a9576b7d1678f60d From 6627d5d00daa45d45d74c91794add74c1fcaf590 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 9 Jul 2024 14:36:05 +0000 Subject: [PATCH 035/101] Minimal build for QIREE Signed-off-by: Daniel Claudino --- CMakeLists.txt | 6 ++++ .../compiler/tests/PyXASMCompilerTester.cpp | 2 ++ quantum/gate/utils/tests/IRUtilsTester.cpp | 2 ++ quantum/observable/CMakeLists.txt | 4 ++- .../pauli/tests/PauliOperatorTester.cpp | 2 ++ quantum/plugins/CMakeLists.txt | 29 +++++++++---------- quantum/plugins/algorithms/CMakeLists.txt | 15 ++++++---- quantum/plugins/circuits/CMakeLists.txt | 9 +++++- .../circuits/uccsd/tests/UCCSDTester.cpp | 3 +- quantum/plugins/circuits/uccsd/uccsd.cpp | 6 ++-- .../ibm/aer/tests/AerAcceleratorTester.cpp | 6 +++- .../qpp/tests/QppAcceleratorTester.cpp | 7 ++++- .../qsim/tests/QsimAcceleratorTester.cpp | 2 ++ .../plugins/xasm/tests/XASMCompilerTester.cpp | 2 ++ xacc/tests/HeterogeneousTester.cpp | 3 +- xacc/tests/XACCAPITester.cpp | 3 ++ 16 files changed, 73 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15452f92d..57b9fb41a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,12 @@ else() message(STATUS "${BoldYellow}Skipping Annealing libraries by default. You can turn it on with -DXACC_BUILD_ANNEALING=ON${ColorReset}") endif() +option(QIREE_MINIMAL_BUILD "Build only components for QIREE CI" OFF) + +if(QIREE_MINIMAL_BUILD) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQIREE_BUILD") +endif() + if(FROM_SETUP_PY AND NOT APPLE) message(STATUS "Running build from setup.py, linking to static libstdc++") set(CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++" CACHE INTERNAL "" FORCE) diff --git a/python/compiler/tests/PyXASMCompilerTester.cpp b/python/compiler/tests/PyXASMCompilerTester.cpp index 44952ebdc..f14b93a0c 100644 --- a/python/compiler/tests/PyXASMCompilerTester.cpp +++ b/python/compiler/tests/PyXASMCompilerTester.cpp @@ -84,6 +84,7 @@ class custom_range : public xacc::quantum::Circuit { std::cout << "KERNEL\n" << IR->getComposites()[0]->toString() << "\n"; } +#ifndef QIREE_BUILD TEST(PyXASMCompilerTester, checkUCCSD) { auto compiler = xacc::getCompiler("pyxasm"); auto IR = compiler -> compile(R"(def ansatz_vqe(buffer, args): @@ -93,6 +94,7 @@ auto compiler = xacc::getCompiler("pyxasm"); std::cout << IR->getComposites()[0]->toString() << "\n"; } +#endif int main(int argc, char **argv) { xacc::Initialize(argc, argv); diff --git a/quantum/gate/utils/tests/IRUtilsTester.cpp b/quantum/gate/utils/tests/IRUtilsTester.cpp index 3dd6b5ed8..3a88e4a87 100644 --- a/quantum/gate/utils/tests/IRUtilsTester.cpp +++ b/quantum/gate/utils/tests/IRUtilsTester.cpp @@ -68,6 +68,7 @@ TEST(IRUtilsTester, checkSimple) { EXPECT_TRUE(result.validate(testCircs)); } +#ifndef QIREE_BUILD TEST(IRUtilsTester, checkObservable) { { auto H_N_2 = xacc::quantum::getObservable( @@ -115,6 +116,7 @@ TEST(IRUtilsTester, checkObservable) { EXPECT_TRUE(result.validate(fsToExe)); } } +#endif int main(int argc, char **argv) { xacc::Initialize(argc, argv); diff --git a/quantum/observable/CMakeLists.txt b/quantum/observable/CMakeLists.txt index e2db87b2c..9b80409a2 100644 --- a/quantum/observable/CMakeLists.txt +++ b/quantum/observable/CMakeLists.txt @@ -1,3 +1,5 @@ add_subdirectory(pauli) add_subdirectory(fermion) -add_subdirectory(transforms) \ No newline at end of file +if(NOT QIREE_MINIMAL_BUILD) +add_subdirectory(transforms) +endif(NOT QIREE_MINIMAL_BUILD) \ No newline at end of file diff --git a/quantum/observable/pauli/tests/PauliOperatorTester.cpp b/quantum/observable/pauli/tests/PauliOperatorTester.cpp index 00d7198e8..7eb2224c0 100644 --- a/quantum/observable/pauli/tests/PauliOperatorTester.cpp +++ b/quantum/observable/pauli/tests/PauliOperatorTester.cpp @@ -545,6 +545,7 @@ TEST(PauliOperatorTester, checkGroupingCommuteCheck) { } } +#ifndef QIREE_BUILD TEST(PauliOperatorTester, checkGroupingQaoaPostProcessLSB) { PauliOperator op; op.fromString("(1.5,0) + (-0.5,0) Z0 Z1 + (-0.5,0) Z0 Z2 + (-0.5,0) Z1 Z2"); @@ -591,6 +592,7 @@ TEST(PauliOperatorTester, checkGroupingQaoaPostProcessMSB) { buffer, xacc::Observable::PostProcessingTask::EXP_VAL_CALC, {}); EXPECT_NEAR(exp_val, 2.0, 0.1); } +#endif TEST(PauliOperatorTester, checkGetBasisRotations) { PauliOperator op; diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index c837b148d..4c2de7587 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -11,23 +11,27 @@ # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ add_subdirectory(ibm) -add_subdirectory(rigetti) -#add_subdirectory(cmr) add_subdirectory(algorithms) -add_subdirectory(decorators) -add_subdirectory(circuits) -add_subdirectory(optimizers) -add_subdirectory(circuit_optimizers) -add_subdirectory(iontrap) add_subdirectory(ionq) -add_subdirectory(placement) -#add_subdirectory(scaffold) add_subdirectory(xasm) add_subdirectory(qpp) add_subdirectory(staq) add_subdirectory(honeywell) + +if(NOT QIREE_MINIMAL_BUILD) +add_subdirectory(placement) +add_subdirectory(iontrap) +add_subdirectory(circuits) +add_subdirectory(optimizers) +add_subdirectory(circuit_optimizers) +add_subdirectory(rigetti) +add_subdirectory(decorators) add_subdirectory(observable_transforms) -#add_subdirectory(jaqal) +add_subdirectory(optimal_control) +add_subdirectory(qsim) +add_subdirectory(atos_qlm) +add_subdirectory(noise_model) +endif() find_library(QRACK_LIBRARY NAMES qrack) if (QRACK_LIBRARY) @@ -41,9 +45,4 @@ if(XACC_BUILD_ANNEALING) add_subdirectory(dwave) endif() -add_subdirectory(optimal_control) -add_subdirectory(qsim) -add_subdirectory(atos_qlm) -add_subdirectory(noise_model) - install (FILES utils/OperatorPool.hpp DESTINATION include/quantum/gate) diff --git a/quantum/plugins/algorithms/CMakeLists.txt b/quantum/plugins/algorithms/CMakeLists.txt index 705bb7f3f..f813f3db7 100644 --- a/quantum/plugins/algorithms/CMakeLists.txt +++ b/quantum/plugins/algorithms/CMakeLists.txt @@ -10,18 +10,23 @@ # Contributors: # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ -add_subdirectory(adapt) + + +if(NOT QIREE_MINIMAL_BUILD) add_subdirectory(vqe) add_subdirectory(rdm) -add_subdirectory(ml) -add_subdirectory(rotoselect) -add_subdirectory(qpt) +add_subdirectory(gradient_strategies) add_subdirectory(qaoa) +add_subdirectory(rotoselect) +add_subdirectory(adapt) add_subdirectory(qpe) -add_subdirectory(gradient_strategies) +add_subdirectory(qpt) +add_subdirectory(ml) add_subdirectory(qite) add_subdirectory(qcmx) add_subdirectory(qeom) +endif(QIREE_MINIMAL_BUILD) + file(GLOB PYDECORATORS ${CMAKE_CURRENT_SOURCE_DIR}/vqe/python/*.py ${CMAKE_CURRENT_SOURCE_DIR}/ml/ddcl/python/*.py) diff --git a/quantum/plugins/circuits/CMakeLists.txt b/quantum/plugins/circuits/CMakeLists.txt index 5ae34dbf5..032a7c72b 100644 --- a/quantum/plugins/circuits/CMakeLists.txt +++ b/quantum/plugins/circuits/CMakeLists.txt @@ -35,6 +35,11 @@ target_include_directories( PUBLIC . range exp hwe qft uccsd ucc1 ucc3 aswap qfast kak ${CMAKE_SOURCE_DIR}/quantum/plugins/utils) +if(QIREE_MINIMAL_BUILD) + list(REMOVE_ITEM SRC kak/kak.cpp qfast/qfast.cpp aswap/aswap.cpp) + list(REMOVE_ITEM INCLUDE_DIRS kak qfast aswap) +endif() + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc PRIVATE xacc-quantum-gate xacc-pauli xacc-fermion) set(_bundle_name xacc_generators) @@ -73,7 +78,9 @@ if(XACC_BUILD_TESTS) add_subdirectory(ucc3/tests) add_subdirectory(aswap/tests) add_subdirectory(qfast/tests) - add_subdirectory(kak/tests) + if(NOT QIREE_MINIMAL_BUILD) + add_subdirectory(kak/tests) + endif() endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) diff --git a/quantum/plugins/circuits/uccsd/tests/UCCSDTester.cpp b/quantum/plugins/circuits/uccsd/tests/UCCSDTester.cpp index bec9a96bf..86f06517e 100644 --- a/quantum/plugins/circuits/uccsd/tests/UCCSDTester.cpp +++ b/quantum/plugins/circuits/uccsd/tests/UCCSDTester.cpp @@ -27,6 +27,7 @@ TEST(UCCSDTester,checkUCCSD) { } +#ifndef QIREE_BUILD TEST(UCCSDTester,checkSingletAdaptedUCCSD) { auto tmp = xacc::getService("uccsd");//std::make_shared(); @@ -48,7 +49,7 @@ TEST(UCCSDTester,checkQubitPool) { std::cout << uccsd->toString() << "\n"; } - +#endif int main(int argc, char** argv) { xacc::Initialize(); diff --git a/quantum/plugins/circuits/uccsd/uccsd.cpp b/quantum/plugins/circuits/uccsd/uccsd.cpp index f2041761f..6f2411532 100644 --- a/quantum/plugins/circuits/uccsd/uccsd.cpp +++ b/quantum/plugins/circuits/uccsd/uccsd.cpp @@ -50,6 +50,7 @@ bool UCCSD::expand(const xacc::HeterogeneousMap &runtimeOptions) { std::map terms; std::vector variables; +#ifndef QIREE_BUILD if (runtimeOptions.stringExists("pool")) { auto pool = xacc::getService(runtimeOptions.getString("pool")); @@ -83,6 +84,7 @@ bool UCCSD::expand(const xacc::HeterogeneousMap &runtimeOptions) { } else { // create UCCSD as it used to +#endif auto nSingle = _nOccupied * _nVirtual; auto nDouble = nSingle * (nSingle + 1) / 2; auto _nParameters = nSingle + nDouble; @@ -212,9 +214,9 @@ bool UCCSD::expand(const xacc::HeterogeneousMap &runtimeOptions) { jw->transform(std::shared_ptr(&myOp, [](Observable *) {})); terms = std::dynamic_pointer_cast(compositeResult)->getTerms(); - +#ifndef QIREE_BUILD } - +#endif auto pi = xacc::constants::pi; int co = 0; auto gateRegistry = xacc::getIRProvider("quantum"); diff --git a/quantum/plugins/ibm/aer/tests/AerAcceleratorTester.cpp b/quantum/plugins/ibm/aer/tests/AerAcceleratorTester.cpp index 59e64c92a..718391d80 100644 --- a/quantum/plugins/ibm/aer/tests/AerAcceleratorTester.cpp +++ b/quantum/plugins/ibm/aer/tests/AerAcceleratorTester.cpp @@ -99,6 +99,8 @@ TEST(AerAcceleratorTester, checkDeuteron) { EXPECT_NEAR(buffer->getExpectationValueZ(), expectedResults[i], 1e-6); } } + +#ifndef QIREE_BUILD TEST(AerAcceleratorTester, checkDeuteronVqeH2) { auto accelerator = xacc::getAccelerator("aer", {std::make_pair("sim-type", "statevector")}); @@ -256,6 +258,7 @@ MEASURE 1 [1] nbShots); } } +#endif TEST(AerAcceleratorTester, checkNoiseJson) { // Single-qubit noise model Json (IBMQ armonk) @@ -600,6 +603,7 @@ TEST(AerAcceleratorTester, testExecutionInfoDensityMat) { EXPECT_NEAR(std::abs((*dm)[3][3] - 0.5), 0.0, 1e-9); } +#ifndef QIREE_BUILD TEST(AerAcceleratorTester, checkDeuteronVqeH2DensityMatrix) { auto accelerator = xacc::getAccelerator("aer", {{"sim-type", "density_matrix"}}); @@ -674,7 +678,7 @@ TEST(AerAcceleratorTester, testDeuteronVqeH3DensityMatrix) { // Expected result: -2.04482 EXPECT_NEAR((*buffer)["opt-val"].as(), -2.04482, 1e-4); } - +#endif TEST(AerAcceleratorTester, checkMatrixProductState) { auto xasmCompiler = xacc::getCompiler("xasm"); auto ir = xasmCompiler->compile(R"(__qpu__ void test1(qbit q) { diff --git a/quantum/plugins/qpp/tests/QppAcceleratorTester.cpp b/quantum/plugins/qpp/tests/QppAcceleratorTester.cpp index fcbce2fad..a44e83f12 100644 --- a/quantum/plugins/qpp/tests/QppAcceleratorTester.cpp +++ b/quantum/plugins/qpp/tests/QppAcceleratorTester.cpp @@ -84,6 +84,7 @@ TEST(QppAcceleratorTester, testDeuteron) } } +#ifndef QIREE_BUILD TEST(QppAcceleratorTester, testDeuteronVqeH2) { // Use Qpp accelerator @@ -215,7 +216,7 @@ MEASURE 1 [1] EXPECT_EQ(buffer->getMeasurementCounts()["11"] + buffer->getMeasurementCounts()["00"], nbShots); } } - +#endif // Port DDCL test suite to QPP /*TEST(QppAcceleratorTester, testDDCL) { @@ -454,6 +455,7 @@ TEST(QppAcceleratorTester, testFsim) } } +#ifndef QIREE_BUILD TEST(QppAcceleratorTester, testDeuteronVqeH3Shots) { // Use Qpp accelerator @@ -538,6 +540,7 @@ TEST(QppAcceleratorTester, testVqeMode) // Expected result: -1.74886 EXPECT_NEAR((*buffer)["opt-val"].as(), -1.74886, 1e-4); } +#endif TEST(QppAcceleratorTester, testExecutionInfo) { @@ -662,6 +665,7 @@ TEST(QppAcceleratorTester, testFtqcApply) EXPECT_TRUE(nb00 > 100 && nb11 > 100); } +#ifndef QIREE_BUILD TEST(QppAcceleratorTester, testMultiControlledGateNativeSim) { auto gateRegistry = xacc::getService("quantum"); @@ -752,6 +756,7 @@ TEST(QppAcceleratorTester, testMultiControlledGateNativeSim) } } } +#endif TEST(QppAcceleratorTester, checkRandomSeed) { auto xasmCompiler = xacc::getCompiler("xasm"); diff --git a/quantum/plugins/qsim/tests/QsimAcceleratorTester.cpp b/quantum/plugins/qsim/tests/QsimAcceleratorTester.cpp index c809450a0..bc92adb79 100644 --- a/quantum/plugins/qsim/tests/QsimAcceleratorTester.cpp +++ b/quantum/plugins/qsim/tests/QsimAcceleratorTester.cpp @@ -280,6 +280,7 @@ TEST(QsimAcceleratorTester, testConditional) { EXPECT_EQ(resultCount, nbTests); } +#ifndef QIREE_BUILD TEST(QsimAcceleratorTester, testMultiControlledGateNativeSim) { auto gateRegistry = xacc::getService("quantum"); auto x = std::make_shared(0); @@ -369,6 +370,7 @@ TEST(QsimAcceleratorTester, testMultiControlledGateNativeSim) { } } } +#endif TEST(QsimAcceleratorTester, checkRandomSeed) { auto accelerator = diff --git a/quantum/plugins/xasm/tests/XASMCompilerTester.cpp b/quantum/plugins/xasm/tests/XASMCompilerTester.cpp index 9d97245e8..510bd26bb 100644 --- a/quantum/plugins/xasm/tests/XASMCompilerTester.cpp +++ b/quantum/plugins/xasm/tests/XASMCompilerTester.cpp @@ -253,6 +253,7 @@ TEST(XASMCompilerTester, checkIfStmt) { std::cout << "KERNEL\n" << IR->getComposites()[0]->toString() << "\n"; } +#ifndef QIREE_BUILD TEST(XASMCompilerTester, checkApplyAll) { auto compiler = xacc::getCompiler("xasm"); auto IR = compiler->compile(R"([&](qbit q) { @@ -285,6 +286,7 @@ TEST(XASMCompilerTester, checkApplyAll) { EXPECT_EQ(1, IR->getComposites().size()); std::cout << "KERNEL\n" << IR->getComposites()[0]->toString() << "\n"; } +#endif TEST(XASMCompilerTester, checkGateOnAll) { diff --git a/xacc/tests/HeterogeneousTester.cpp b/xacc/tests/HeterogeneousTester.cpp index 8ba2135fe..9fed43eb6 100644 --- a/xacc/tests/HeterogeneousTester.cpp +++ b/xacc/tests/HeterogeneousTester.cpp @@ -117,6 +117,7 @@ TEST(HeterogeneousMapTester, checkSimple) { m4.print(std::cout); } +#ifndef QIREE_BUILD TEST(HeterogeneousMapTester, checkVQE) { using namespace xacc; class TestObservable : public xacc::Observable { @@ -153,7 +154,7 @@ TEST(HeterogeneousMapTester, checkVQE) { vqe->initialize(options); } - +#endif TEST(HeterogeneousMapTester, checkMerge) { xacc::HeterogeneousMap c; c.insert("intkey", 1); diff --git a/xacc/tests/XACCAPITester.cpp b/xacc/tests/XACCAPITester.cpp index 79d01c5b6..0e08b3b64 100644 --- a/xacc/tests/XACCAPITester.cpp +++ b/xacc/tests/XACCAPITester.cpp @@ -115,6 +115,7 @@ CX(q[1],q[0]); std::cout << function2->toString() << "\n"; } +#ifndef QIREE_BUILD TEST(XACCAPITester, checkXasmBug) { xacc::qasm(R"(.compiler xasm .circuit ansatz3 @@ -132,6 +133,8 @@ exp_i_theta(q, s, {{"pauli", "X0 Z1 Y2 - X2 Z1 Y0"}}); std::cout << function3->toString() << "\n"; } +#endif + int main(int argc, char **argv) { xacc::Initialize(); ::testing::InitGoogleTest(&argc, argv); From 2d0e58f55a6cc848d677febf7b0dc559925802cf Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 9 Jul 2024 10:50:54 -0400 Subject: [PATCH 036/101] WIP --- .gitmodules | 2 +- quantum/observable/pauli/CMakeLists.txt | 23 +- quantum/observable/pauli/PauliOperator.cpp | 3 +- .../plugins/algorithms/ml/ddcl/CMakeLists.txt | 3 +- tpls/nlopt | 2 +- .../nlopt/src/api/nlopt-in.hpp | 559 ++++++++++++++++++ 6 files changed, 578 insertions(+), 14 deletions(-) create mode 100644 xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp diff --git a/.gitmodules b/.gitmodules index ef75a52d5..3d7295622 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/dwavesystems/minorminer [submodule "tpls/nlopt"] path = tpls/nlopt - url = https://github.com/stevengj/nlopt + url = https://github.com/ORNL-QCI/nlopt [submodule "quantum/plugins/dwave/tpls/legacy-sapi-clients"] path = quantum/plugins/dwave/tpls/legacy-sapi-clients url = https://github.com/ornl-qci/legacy-sapi-clients diff --git a/quantum/observable/pauli/CMakeLists.txt b/quantum/observable/pauli/CMakeLists.txt index d804b85fb..b0f68c313 100644 --- a/quantum/observable/pauli/CMakeLists.txt +++ b/quantum/observable/pauli/CMakeLists.txt @@ -23,15 +23,22 @@ usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC) usFunctionGenerateBundleInit(TARGET ${LIBRARY_NAME} OUT SRC) add_library(${LIBRARY_NAME} SHARED ${SRC}) +set(EIGEN_INCLUDE_DIR "${EIGEN_INCLUDE_DIR}") +message("EIGEN_INCLUDE_DIR:${EIGEN_INCLUDE_DIR}") target_include_directories(${LIBRARY_NAME} - PUBLIC - . ${CMAKE_SOURCE_DIR}/tpls/armadillo - ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/generated - ${CMAKE_SOURCE_DIR}/tpls/taocpp - ${EIGEN_INCLUDE_DIR} - ${CMAKE_BINARY_DIR}) + PUBLIC + "${EIGEN_INCLUDE_DIR}" + "${EIGEN_INCLUDE_DIR} " + "${EIGEN_INCLUDE_DIR}/POOOOOP" + "${EIGEN_INCLUDE_DIR}"/POOOOOP + ${CMAKE_SOURCE_DIR}/tpls/armadillo + ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/generated + ${CMAKE_SOURCE_DIR}/tpls/taocpp + ${CMAKE_BINARY_DIR} +) +target_link_libraries(${LIBRARY_NAME} PUBLIC Eigen3::Eigen) add_dependencies(${LIBRARY_NAME} antlr4_shared) diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index 198f1d2a7..771a591cb 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -13,7 +13,6 @@ #include "PauliOperator.hpp" #include "CompositeInstruction.hpp" #include "IRProvider.hpp" -#include #include #include #include @@ -1108,7 +1107,7 @@ std::vector> PauliOperator::getMeasurement // the idea is that, for something like VQE, we only need to know // the qubits that need to be measure in the X or Y basis - // so we map the index of the qubit, to the corresponding + // so we map the index of the qubit, to the corresponding // rotation operators, then later add measure to all qubits std::vector> basisRotations; diff --git a/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt b/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt index 55ad9cfa9..7290ae289 100644 --- a/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt +++ b/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt @@ -21,8 +21,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC . - ${EIGEN_INCLUDE_DIR}) + PUBLIC SYSTEM "${EIGEN_INCLUDE_DIR}") target_link_libraries(${LIBRARY_NAME} PUBLIC xacc) diff --git a/tpls/nlopt b/tpls/nlopt index 945d055b9..dc4ad82b6 160000 --- a/tpls/nlopt +++ b/tpls/nlopt @@ -1 +1 @@ -Subproject commit 945d055b98be2db327f694b36ba507c41e1955fc +Subproject commit dc4ad82b6e374619efa423b585f7f96b875b2cb7 diff --git a/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp b/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp new file mode 100644 index 000000000..7b9a42913 --- /dev/null +++ b/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp @@ -0,0 +1,559 @@ +/* Copyright (c) 2007-2011 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// C++ style wrapper around NLopt API +// nlopt.hpp is AUTOMATICALLY GENERATED from nlopt-in.hpp - edit the latter! + +#ifndef NLOPT_HPP +#define NLOPT_HPP + +#include + +#include +#include +#include +#include +#include +#include + +// convenience overloading for below (not in nlopt:: since has nlopt_ prefix) +inline nlopt_result nlopt_get_initial_step(const nlopt_opt opt, double *dx) { + return nlopt_get_initial_step(opt, (const double *) NULL, dx); +} + +namespace nlopt { + + ////////////////////////////////////////////////////////////////////// + // nlopt::* namespace versions of the C enumerated types + // AUTOMATICALLY GENERATED, DO NOT EDIT + // GEN_ENUMS_HERE + ////////////////////////////////////////////////////////////////////// + + typedef nlopt_func func; // nlopt::func synoynm + typedef nlopt_mfunc mfunc; // nlopt::mfunc synoynm + + // alternative to nlopt_func that takes std::vector + // ... unfortunately requires a data copy + typedef double (*vfunc)(const std::vector &x, + std::vector &grad, void *data); + + ////////////////////////////////////////////////////////////////////// + + // NLopt-specific exceptions (corresponding to error codes): + class roundoff_limited : public std::runtime_error { + public: + roundoff_limited() : std::runtime_error("nlopt roundoff-limited") {} + }; + + class forced_stop : public std::runtime_error { + public: + forced_stop() : std::runtime_error("nlopt forced stop") {} + }; + + ////////////////////////////////////////////////////////////////////// + + class opt { + private: + nlopt_opt o; + + void mythrow(nlopt_result ret) const { + switch (ret) { + case NLOPT_FAILURE: throw std::runtime_error(get_errmsg() ? get_errmsg() : "nlopt failure"); + case NLOPT_OUT_OF_MEMORY: throw std::bad_alloc(); + case NLOPT_INVALID_ARGS: throw std::invalid_argument(get_errmsg() ? get_errmsg() : "nlopt invalid argument"); + case NLOPT_ROUNDOFF_LIMITED: throw roundoff_limited(); + case NLOPT_FORCED_STOP: throw forced_stop(); + default: break; + } + } + + typedef struct { + opt *o; + mfunc mf; func f; void *f_data; + vfunc vf; + nlopt_munge munge_destroy, munge_copy; // non-NULL for SWIG wrappers + } myfunc_data; + + // free/destroy f_data in nlopt_destroy and nlopt_copy, respectively + static void *free_myfunc_data(void *p) { + myfunc_data *d = (myfunc_data *) p; + if (d) { + if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data); + delete d; + } + return NULL; + } + static void *dup_myfunc_data(void *p) { + myfunc_data *d = (myfunc_data *) p; + if (d) { + void *f_data; + if (d->f_data && d->munge_copy) { + f_data = d->munge_copy(d->f_data); + if (!f_data) return NULL; + } + else + f_data = d->f_data; + myfunc_data *dnew = new myfunc_data; + if (dnew) { + *dnew = *d; + dnew->f_data = f_data; + } + return (void*) dnew; + } + else return NULL; + } + + // nlopt_func wrapper that catches exceptions + static double myfunc(unsigned n, const double *x, double *grad, void *d_) { + myfunc_data *d = reinterpret_cast(d_); + try { + return d->f(n, x, grad, d->f_data); + } + catch (std::bad_alloc&) + { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; } + catch (std::invalid_argument&) + { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; } + catch (roundoff_limited&) + { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; } + catch (forced_stop&) + { d->o->forced_stop_reason = NLOPT_FORCED_STOP; } + catch (...) + { d->o->forced_stop_reason = NLOPT_FAILURE; } + d->o->force_stop(); // stop gracefully, opt::optimize will re-throw + return HUGE_VAL; + } + + // nlopt_mfunc wrapper that catches exceptions + static void mymfunc(unsigned m, double *result, + unsigned n, const double *x, double *grad, void *d_) { + myfunc_data *d = reinterpret_cast(d_); + try { + d->mf(m, result, n, x, grad, d->f_data); + return; + } + catch (std::bad_alloc&) + { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; } + catch (std::invalid_argument&) + { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; } + catch (roundoff_limited&) + { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; } + catch (forced_stop&) + { d->o->forced_stop_reason = NLOPT_FORCED_STOP; } + catch (...) + { d->o->forced_stop_reason = NLOPT_FAILURE; } + d->o->force_stop(); // stop gracefully, opt::optimize will re-throw + for (unsigned i = 0; i < m; ++i) result[i] = HUGE_VAL; + } + + std::vector xtmp, gradtmp, gradtmp0; // scratch for myvfunc + + // nlopt_func wrapper, using std::vector + static double myvfunc(unsigned n, const double *x, double *grad, void *d_){ + myfunc_data *d = reinterpret_cast(d_); + try { + std::vector &xv = d->o->xtmp; + if (n) std::memcpy(&xv[0], x, n * sizeof(double)); + double val=d->vf(xv, grad ? d->o->gradtmp : d->o->gradtmp0, d->f_data); + if (grad && n) { + std::vector &gradv = d->o->gradtmp; + std::memcpy(grad, &gradv[0], n * sizeof(double)); + } + return val; + } + catch (std::bad_alloc&) + { d->o->forced_stop_reason = NLOPT_OUT_OF_MEMORY; } + catch (std::invalid_argument&) + { d->o->forced_stop_reason = NLOPT_INVALID_ARGS; } + catch (roundoff_limited&) + { d->o->forced_stop_reason = NLOPT_ROUNDOFF_LIMITED; } + catch (forced_stop&) + { d->o->forced_stop_reason = NLOPT_FORCED_STOP; } + catch (...) + { d->o->forced_stop_reason = NLOPT_FAILURE; } + d->o->force_stop(); // stop gracefully, opt::optimize will re-throw + return HUGE_VAL; + } + + void alloc_tmp() { + if (xtmp.size() != nlopt_get_dimension(o)) { + xtmp = std::vector(nlopt_get_dimension(o)); + gradtmp = std::vector(nlopt_get_dimension(o)); + } + } + + result last_result; + double last_optf; + nlopt_result forced_stop_reason; + + public: + // Constructors etc. + opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0), + last_result(nlopt::FAILURE), last_optf(HUGE_VAL), + forced_stop_reason(NLOPT_FORCED_STOP) {} + ~opt() { nlopt_destroy(o); } + opt(algorithm a, unsigned n) : + o(nlopt_create(nlopt_algorithm(a), n)), + xtmp(0), gradtmp(0), gradtmp0(0), + last_result(nlopt::FAILURE), last_optf(HUGE_VAL), + forced_stop_reason(NLOPT_FORCED_STOP) { + if (!o) throw std::bad_alloc(); + nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data); + } + opt(const char * algo_str, unsigned n) : + o(NULL), xtmp(0), gradtmp(0), gradtmp0(0), + last_result(nlopt::FAILURE), last_optf(HUGE_VAL), + forced_stop_reason(NLOPT_FORCED_STOP) { + const nlopt_algorithm a = nlopt_algorithm_from_string(algo_str); + if (a < 0) + throw std::invalid_argument("wrong algorithm string"); + o = nlopt_create(a, n); + if (!o) throw std::bad_alloc(); + nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data); + } + opt(const opt& f) : o(nlopt_copy(f.o)), + xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0), + last_result(f.last_result), last_optf(f.last_optf), + forced_stop_reason(f.forced_stop_reason) { + if (f.o && !o) throw std::bad_alloc(); + } + opt& operator=(opt const& f) { + if (this == &f) return *this; // self-assignment + nlopt_destroy(o); + o = nlopt_copy(f.o); + if (f.o && !o) throw std::bad_alloc(); + xtmp = f.xtmp; gradtmp = f.gradtmp; + last_result = f.last_result; last_optf = f.last_optf; + forced_stop_reason = f.forced_stop_reason; + return *this; + } + + // Do the optimization: + result optimize(std::vector &x, double &opt_f) { + if (o && nlopt_get_dimension(o) != x.size()) + throw std::invalid_argument("dimension mismatch"); + forced_stop_reason = NLOPT_FORCED_STOP; + nlopt_result ret = nlopt_optimize(o, x.empty() ? NULL : &x[0], &opt_f); + last_result = result(ret); + last_optf = opt_f; + if (ret == NLOPT_FORCED_STOP) + mythrow(forced_stop_reason); + mythrow(ret); + return last_result; + } + + // variant mainly useful for SWIG wrappers: + std::vector optimize(const std::vector &x0) { + std::vector x(x0); + last_result = optimize(x, last_optf); + return x; + } + result last_optimize_result() const { return last_result; } + double last_optimum_value() const { return last_optf; } + + // accessors: + algorithm get_algorithm() const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + return algorithm(nlopt_get_algorithm(o)); + } + const char *get_algorithm_name() const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + return nlopt_algorithm_name(nlopt_get_algorithm(o)); + } + unsigned get_dimension() const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + return nlopt_get_dimension(o); + } + + // Set the objective function + void set_min_objective(func f, void *f_data) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o + } + void set_min_objective(vfunc vf, void *f_data) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_set_min_objective(o, myvfunc, d)); // d freed via o + alloc_tmp(); + } + void set_max_objective(func f, void *f_data) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o + } + void set_max_objective(vfunc vf, void *f_data) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_set_max_objective(o, myvfunc, d)); // d freed via o + alloc_tmp(); + } + + // for internal use in SWIG wrappers -- variant that + // takes ownership of f_data, with munging for destroy/copy + void set_min_objective(func f, void *f_data, + nlopt_munge md, nlopt_munge mc) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_set_min_objective(o, myfunc, d)); // d freed via o + } + void set_max_objective(func f, void *f_data, + nlopt_munge md, nlopt_munge mc) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_set_max_objective(o, myfunc, d)); // d freed via o + } + + // Nonlinear constraints: + + void remove_inequality_constraints() { + nlopt_result ret = nlopt_remove_inequality_constraints(o); + mythrow(ret); + } + void add_inequality_constraint(func f, void *f_data, double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol)); + } + void add_inequality_constraint(vfunc vf, void *f_data, double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol)); + alloc_tmp(); + } + void add_inequality_mconstraint(mfunc mf, void *f_data, + const std::vector &tol) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d, + tol.empty() ? NULL : &tol[0])); + } + + void remove_equality_constraints() { + nlopt_result ret = nlopt_remove_equality_constraints(o); + mythrow(ret); + } + void add_equality_constraint(func f, void *f_data, double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol)); + } + void add_equality_constraint(vfunc vf, void *f_data, double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = NULL; d->f_data = f_data; d->mf = NULL; d->vf = vf; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol)); + alloc_tmp(); + } + void add_equality_mconstraint(mfunc mf, void *f_data, + const std::vector &tol) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL; + d->munge_destroy = d->munge_copy = NULL; + mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d, + tol.empty() ? NULL : &tol[0])); + } + + // For internal use in SWIG wrappers (see also above) + void add_inequality_constraint(func f, void *f_data, + nlopt_munge md, nlopt_munge mc, + double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol)); + } + void add_equality_constraint(func f, void *f_data, + nlopt_munge md, nlopt_munge mc, + double tol=0) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->f = f; d->f_data = f_data; d->mf = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol)); + } + void add_inequality_mconstraint(mfunc mf, void *f_data, + nlopt_munge md, nlopt_munge mc, + const std::vector &tol) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d, + tol.empty() ? NULL : &tol[0])); + } + void add_equality_mconstraint(mfunc mf, void *f_data, + nlopt_munge md, nlopt_munge mc, + const std::vector &tol) { + myfunc_data *d = new myfunc_data; + if (!d) throw std::bad_alloc(); + d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL; + d->munge_destroy = md; d->munge_copy = mc; + mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d, + tol.empty() ? NULL : &tol[0])); + } + +#define NLOPT_GETSET_VEC(name) \ + void set_##name(double val) { \ + mythrow(nlopt_set_##name##1(o, val)); \ + } \ + void get_##name(std::vector &v) const { \ + if (o && nlopt_get_dimension(o) != v.size()) \ + throw std::invalid_argument("dimension mismatch"); \ + mythrow(nlopt_get_##name(o, v.empty() ? NULL : &v[0])); \ + } \ + std::vector get_##name() const { \ + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \ + std::vector v(nlopt_get_dimension(o)); \ + get_##name(v); \ + return v; \ + } \ + void set_##name(const std::vector &v) { \ + if (o && nlopt_get_dimension(o) != v.size()) \ + throw std::invalid_argument("dimension mismatch"); \ + mythrow(nlopt_set_##name(o, v.empty() ? NULL : &v[0])); \ + } + + NLOPT_GETSET_VEC(lower_bounds) + NLOPT_GETSET_VEC(upper_bounds) + + // stopping criteria: + +#define NLOPT_GETSET(T, name) \ + T get_##name() const { \ + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); \ + return nlopt_get_##name(o); \ + } \ + void set_##name(T name) { \ + mythrow(nlopt_set_##name(o, name)); \ + } + NLOPT_GETSET(double, stopval) + NLOPT_GETSET(double, ftol_rel) + NLOPT_GETSET(double, ftol_abs) + NLOPT_GETSET(double, xtol_rel) + NLOPT_GETSET_VEC(xtol_abs) + NLOPT_GETSET_VEC(x_weights) + NLOPT_GETSET(int, maxeval) + + int get_numevals() const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + return nlopt_get_numevals(o); + } + + NLOPT_GETSET(double, maxtime) + + NLOPT_GETSET(int, force_stop) + void force_stop() { set_force_stop(1); } + + const char *get_errmsg() const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + return nlopt_get_errmsg(o); + } + + // algorithm-specific parameters: + + void set_local_optimizer(const opt &lo) { + nlopt_result ret = nlopt_set_local_optimizer(o, lo.o); + mythrow(ret); + } + + NLOPT_GETSET(unsigned, population) + NLOPT_GETSET(unsigned, vector_storage) + NLOPT_GETSET_VEC(initial_step) + + void set_default_initial_step(const std::vector &x) { + nlopt_result ret + = nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]); + mythrow(ret); + } + void get_initial_step(const std::vector &x, std::vector &dx) const { + if (o && (nlopt_get_dimension(o) != x.size() + || nlopt_get_dimension(o) != dx.size())) + throw std::invalid_argument("dimension mismatch"); + nlopt_result ret = nlopt_get_initial_step(o, x.empty() ? NULL : &x[0], + dx.empty() ? NULL : &dx[0]); + mythrow(ret); + } + std::vector get_initial_step_(const std::vector &x) const { + if (!o) throw std::runtime_error("uninitialized nlopt::opt"); + std::vector v(nlopt_get_dimension(o)); + get_initial_step(x, v); + return v; + } + }; + +#undef NLOPT_GETSET +#undef NLOPT_GETSET_VEC + + ////////////////////////////////////////////////////////////////////// + + inline void srand(unsigned long seed) { nlopt_srand(seed); } + inline void srand_time() { nlopt_srand_time(); } + inline void version(int &major, int &minor, int &bugfix) { + nlopt_version(&major, &minor, &bugfix); + } + inline int version_major() { + int major, minor, bugfix; + nlopt_version(&major, &minor, &bugfix); + return major; + } + inline int version_minor() { + int major, minor, bugfix; + nlopt_version(&major, &minor, &bugfix); + return minor; + } + inline int version_bugfix() { + int major, minor, bugfix; + nlopt_version(&major, &minor, &bugfix); + return bugfix; + } + inline const char *algorithm_name(algorithm a) { + return nlopt_algorithm_name(nlopt_algorithm(a)); + } + + ////////////////////////////////////////////////////////////////////// + +} // namespace nlopt + +#endif /* NLOPT_HPP */ From 8974572119bc37ee9d83fc12afdd65aafb00f58f Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 9 Jul 2024 15:17:38 +0000 Subject: [PATCH 037/101] Cleaned up includes in PauliOperator.cpp Signed-off-by: Daniel Claudino --- quantum/observable/pauli/PauliOperator.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index 198f1d2a7..b921c7961 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -13,23 +13,11 @@ #include "PauliOperator.hpp" #include "CompositeInstruction.hpp" #include "IRProvider.hpp" -#include -#include -#include -#include -#include -#include -#include -#include "Instruction.hpp" -#include "Observable.hpp" #include "xacc.hpp" #include "xacc_service.hpp" - #include - #include "PauliOperatorLexer.h" #include "PauliListenerImpl.hpp" - #include namespace xacc { From fb3563dd76722dad4525e3f4049d938466722446 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 9 Jul 2024 19:13:02 +0000 Subject: [PATCH 038/101] Implemented GSL optimizers Signed-off-by: Daniel Claudino --- CMakeLists.txt | 2 + quantum/plugins/optimizers/CMakeLists.txt | 4 + quantum/plugins/optimizers/gsl/CMakeLists.txt | 53 ++++ .../plugins/optimizers/gsl/gsl_optimizer.cpp | 245 ++++++++++++++++++ .../plugins/optimizers/gsl/gsl_optimizer.hpp | 24 ++ quantum/plugins/optimizers/gsl/manifest.json | 6 + .../optimizers/gsl/tests/CMakeLists.txt | 2 + .../gsl/tests/GSLOptimizerTester.cpp | 96 +++++++ tpls/CMakeLists.txt | 4 + tpls/gsl/CMakeLists.txt | 45 ++++ 10 files changed, 481 insertions(+) create mode 100644 quantum/plugins/optimizers/gsl/CMakeLists.txt create mode 100644 quantum/plugins/optimizers/gsl/gsl_optimizer.cpp create mode 100644 quantum/plugins/optimizers/gsl/gsl_optimizer.hpp create mode 100644 quantum/plugins/optimizers/gsl/manifest.json create mode 100644 quantum/plugins/optimizers/gsl/tests/CMakeLists.txt create mode 100644 quantum/plugins/optimizers/gsl/tests/GSLOptimizerTester.cpp create mode 100644 tpls/gsl/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 15452f92d..d4d1f687f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ option(XACC_ENSMALLEN_INCLUDE_DIR "Path to ensmallen.hpp for mlpack optimizer" " option(XACC_ARMADILLO_INCLUDE_DIR "Path to armadillo header for mlpack optimizer" "") option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) option(XACC_BUILD_SCIPY "Build Scipy optimizer plugin" OFF) +option(XACC_BUILD_GSL "Build GNU Scientific Library optimizer plugin" OFF) + if(XACC_BUILD_ANNEALING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") else() diff --git a/quantum/plugins/optimizers/CMakeLists.txt b/quantum/plugins/optimizers/CMakeLists.txt index bcfcf75ec..70165c654 100644 --- a/quantum/plugins/optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/CMakeLists.txt @@ -1,5 +1,9 @@ add_subdirectory(nlopt-optimizers) add_subdirectory(mlpack) + +if(XACC_BUILD_GSL) +add_subdirectory(gsl) +endif() if(XACC_BUILD_SCIPY) execute_process(COMMAND ${Python_EXECUTABLE} -c "import scipy" RESULT_VARIABLE SCIPY_EXISTS) if(SCIPY_EXISTS EQUAL "1") diff --git a/quantum/plugins/optimizers/gsl/CMakeLists.txt b/quantum/plugins/optimizers/gsl/CMakeLists.txt new file mode 100644 index 000000000..bbfb44c90 --- /dev/null +++ b/quantum/plugins/optimizers/gsl/CMakeLists.txt @@ -0,0 +1,53 @@ +message(STATUS "${BoldGreen}Building GSL Optimizer.${ColorReset}") +set(LIBRARY_NAME xacc-gsl-optimizer) + +file(GLOB + SRC + gsl_optimizer.cpp) + +usfunctiongetresourcesource(TARGET + ${LIBRARY_NAME} + OUT + SRC) +usfunctiongeneratebundleinit(TARGET + ${LIBRARY_NAME} + OUT + SRC) + +add_library(${LIBRARY_NAME} SHARED ${SRC}) +find_package(GSL REQUIRED) +target_include_directories(${LIBRARY_NAME} + PUBLIC . ${GSL_INCLUDE_DIR}) + +target_link_libraries(${LIBRARY_NAME} PUBLIC xacc GSL::gsl GSL::gslcblas) + +set(_bundle_name xacc_optimizer_gsl) +set_target_properties(${LIBRARY_NAME} + PROPERTIES COMPILE_DEFINITIONS + US_BUNDLE_NAME=${_bundle_name} + US_BUNDLE_NAME + ${_bundle_name}) + +usfunctionembedresources(TARGET + ${LIBRARY_NAME} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + FILES + manifest.json) + +if(APPLE) + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "@loader_path/../lib") + set_target_properties(${LIBRARY_NAME} + PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +else() + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") + set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") +endif() + +if(XACC_BUILD_TESTS) + add_subdirectory(tests) +endif() + +install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) diff --git a/quantum/plugins/optimizers/gsl/gsl_optimizer.cpp b/quantum/plugins/optimizers/gsl/gsl_optimizer.cpp new file mode 100644 index 000000000..77f761bc0 --- /dev/null +++ b/quantum/plugins/optimizers/gsl/gsl_optimizer.cpp @@ -0,0 +1,245 @@ +#include "gsl_optimizer.hpp" +#include "xacc_plugin.hpp" +#include + +struct GSLFunctionWrapper { + xacc::OptFunction &function; + std::vector grad; + + double operator()(const gsl_vector *v) { + std::vector x(v->size); + for (size_t i = 0; i < v->size; ++i) { + x[i] = gsl_vector_get(v, i); + } + if (grad.empty()) { + return function(std::move(x)); + } else { + return function(x, grad); + } + } + + void getGradient(gsl_vector *df) { + for (size_t i = 0; i < grad.size(); ++i) { + gsl_vector_set(df, i, grad[i]); + } + } +}; + +namespace xacc { + +const std::string GSLOptimizer::get_algorithm() const { + std::string optimizerAlgo = "COBYLA"; + if (options.stringExists("algorithm")) { + optimizerAlgo = options.getString("algorithm"); + } + if (options.stringExists("scipy-optimizer")) { + optimizerAlgo = options.getString("scipy-optimizer"); + } + return optimizerAlgo; +} + +const bool GSLOptimizer::isGradientBased() const { + + std::string optimizerAlgo = "cobyla"; + if (options.stringExists("algorithm")) { + optimizerAlgo = options.getString("algorithm"); + } + if (options.stringExists("scipy-optimizer")) { + optimizerAlgo = options.getString("scipy-optimizer"); + } + + if (options.stringExists("optimizer")) { + optimizerAlgo = options.getString("optimizer"); + } + + if (optimizerAlgo == "bfgs") { + return true; + } else { + return false; + } +} + +OptResult GSLOptimizer::optimize(OptFunction &function) { + + bool maximize = false; + if (options.keyExists("maximize")) { + xacc::info("Turning on maximize!"); + maximize = options.get("maximize"); + } + + std::string algo = "COBYLA"; + if (options.stringExists("algorithm")) { + algo = options.getString("algorithm"); + } + if (options.stringExists("gsl-optimizer")) { + algo = options.getString("gsl-optimizer"); + } + if (options.stringExists("optimizer")) { + algo = options.getString("optimizer"); + } + + if (algo == "cobyla" || algo == "COBYLA") { + algo = "COBYLA"; + } else if (algo == "nelder-mead" || algo == "Nelder-Mead") { + algo = "Nelder-Mead"; + } else if (algo == "bfgs" || algo == "BFGS" || algo == "l-bfgs") { + algo = "BFGS"; + } else { + xacc::XACCLogger::instance()->error("Invalid optimizer at this time: " + + algo); + } + + double tol = 1e-6; + if (options.keyExists("ftol")) { + tol = options.get("ftol"); + xacc::info("[GSL] function tolerance set to " + std::to_string(tol)); + } + if (options.keyExists("gsl-ftol")) { + tol = options.get("ftol"); + xacc::info("[GSL] function tolerance set to " + std::to_string(tol)); + } + + int maxeval = 1000; + if (options.keyExists("maxeval")) { + maxeval = options.get("maxeval"); + xacc::info("[GSL] max function evaluations set to " + + std::to_string(maxeval)); + } + if (options.keyExists("gsl-maxeval")) { + maxeval = options.get("maxeval"); + xacc::info("[GSL] max function evaluations set to " + + std::to_string(maxeval)); + } + + double step = 1.0e-4; + if (options.keyExists("step-size")) { + step = options.get("step-size"); + xacc::info("[GSL] step size set to " + std::to_string(step)); + } + if (options.keyExists("gsl-step-size")) { + step = options.get("gsl-step-size"); + xacc::info("[GSL] step size set to " + std::to_string(step)); + } + + std::vector x(function.dimensions()); + if (options.keyExists>("initial-parameters")) { + x = options.get_with_throw>("initial-parameters"); + } else if (options.keyExists>("initial-parameters")) { + auto tmpx = options.get>("initial-parameters"); + x = std::vector(tmpx.begin(), tmpx.end()); + } + + auto dim = function.dimensions(); + gsl_vector *theta = gsl_vector_alloc(dim); + for (size_t i = 0; i < dim; ++i) { + gsl_vector_set(theta, i, x[i]); + } + + GSLFunctionWrapper wrapper{function}; + double minVal; + std::vector result(dim); + if (isGradientBased()) { + + wrapper.grad.resize(dim); + gsl_multimin_function_fdf gslFunction; + gslFunction.n = dim; + + gslFunction.f = [](const gsl_vector *v, void *params) -> double { + GSLFunctionWrapper *w = static_cast(params); + return (*w)(v); + }; + + gslFunction.df = [](const gsl_vector *v, void *params, gsl_vector *df) { + GSLFunctionWrapper *w = static_cast(params); + w->getGradient(df); + }; + + // I don't understand why, but this seems kinda redundant + gslFunction.fdf = [](const gsl_vector *v, void *params, double *f, + gsl_vector *df) { + GSLFunctionWrapper *w = static_cast(params); + (*f) = (*w)(v); + w->getGradient(df); + }; + + gslFunction.params = &wrapper; + + const gsl_multimin_fdfminimizer_type *T = gsl_multimin_fdfminimizer_conjugate_fr; + gsl_multimin_fdfminimizer *s = gsl_multimin_fdfminimizer_alloc(T, dim); + + int set_status = gsl_multimin_fdfminimizer_set(s, &gslFunction, theta, 0.01, 1e-4); + if (set_status) { + gsl_multimin_fdfminimizer_free(s); + gsl_vector_free(theta); + throw std::runtime_error("Failed to set the minimizer."); + } + + int status, iter = 0; + do { + iter++; + status = gsl_multimin_fdfminimizer_iterate(s); + + if (status) + break; + + // Check for convergence using gradient norm + status = gsl_multimin_test_gradient(s->gradient, 1e-4); + + } while (status == GSL_CONTINUE && iter < 100); + + // std::vector result(dim); + for (size_t i = 0; i < dim; ++i) { + result[i] = gsl_vector_get(s->x, i); + } + + minVal = s->f; + gsl_vector_free(theta); + gsl_multimin_fdfminimizer_free(s); + + } else { + + gsl_multimin_function gslFunction; + gslFunction.n = dim; + gslFunction.f = [](const gsl_vector *v, void *params) -> double { + GSLFunctionWrapper *w = static_cast(params); + return (*w)(v); + }; + + gslFunction.params = &wrapper; + + gsl_vector *steps = gsl_vector_alloc(gslFunction.n); + gsl_vector_set_all(steps, step); + + const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex2; + gsl_multimin_fminimizer *s = + gsl_multimin_fminimizer_alloc(T, gslFunction.n); + gsl_multimin_fminimizer_set(s, &gslFunction, theta, steps); + + int status, iter; + double size; + do { + iter++; + status = gsl_multimin_fminimizer_iterate(s); + + if (status) + break; + + size = gsl_multimin_fminimizer_size(s); + status = gsl_multimin_test_size(size, 1e-4); + } while (status == GSL_CONTINUE && iter < 100); + + std::vector result(gslFunction.n); + for (size_t i = 0; i < gslFunction.n; ++i) { + result[i] = gsl_vector_get(s->x, i); + } + + minVal = s->fval; + + gsl_multimin_fminimizer_free(s); + gsl_vector_free(theta); + } + + return {minVal, result}; +} +} // namespace xacc +REGISTER_OPTIMIZER(xacc::GSLOptimizer) \ No newline at end of file diff --git a/quantum/plugins/optimizers/gsl/gsl_optimizer.hpp b/quantum/plugins/optimizers/gsl/gsl_optimizer.hpp new file mode 100644 index 000000000..8e33706f3 --- /dev/null +++ b/quantum/plugins/optimizers/gsl/gsl_optimizer.hpp @@ -0,0 +1,24 @@ +#ifndef GSL_OPTIMIZER_HPP +#define GSL_OPTIMIZER_HPP + +#include +#include +#include + +namespace xacc { + +class GSLOptimizer : public xacc::Optimizer { +public: + GSLOptimizer() = default; + ~GSLOptimizer() = default; + + const std::string name() const override { return "gsl"; } + const std::string description() const override { return ""; } + + OptResult optimize(OptFunction &function) override; + const bool isGradientBased() const override; + virtual const std::string get_algorithm() const override; +}; + +} // namespace xacc +#endif \ No newline at end of file diff --git a/quantum/plugins/optimizers/gsl/manifest.json b/quantum/plugins/optimizers/gsl/manifest.json new file mode 100644 index 000000000..279423cdb --- /dev/null +++ b/quantum/plugins/optimizers/gsl/manifest.json @@ -0,0 +1,6 @@ +{ + "bundle.symbolic_name" : "xacc_optimizer_gsl", + "bundle.activator" : true, + "bundle.name" : "XACC GNU Scientific Library Optimizers", + "bundle.description" : "" +} diff --git a/quantum/plugins/optimizers/gsl/tests/CMakeLists.txt b/quantum/plugins/optimizers/gsl/tests/CMakeLists.txt new file mode 100644 index 000000000..cfa3392d7 --- /dev/null +++ b/quantum/plugins/optimizers/gsl/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_xacc_test(GSLOptimizer) +target_link_libraries(GSLOptimizerTester xacc) \ No newline at end of file diff --git a/quantum/plugins/optimizers/gsl/tests/GSLOptimizerTester.cpp b/quantum/plugins/optimizers/gsl/tests/GSLOptimizerTester.cpp new file mode 100644 index 000000000..823860411 --- /dev/null +++ b/quantum/plugins/optimizers/gsl/tests/GSLOptimizerTester.cpp @@ -0,0 +1,96 @@ +#include +#include "xacc.hpp" +#include "xacc_service.hpp" + +using namespace xacc; + +TEST(GSLOptimizerTester, checkSimple) { + + auto optimizer = + xacc::getService("gsl"); + + OptFunction f([](const std::vector &x, + std::vector &g) { + return x[0] * x[0] + 5; }, + 1); + + EXPECT_EQ(optimizer->name(), "gsl"); + EXPECT_EQ(1, f.dimensions()); + + optimizer->setOptions(HeterogeneousMap{std::make_pair("maxeval", 20)}); + + auto result = optimizer->optimize(f); + EXPECT_EQ(5.0, result.first); + EXPECT_EQ(result.second[0], 0.0); +} + +TEST(GSLOptimizerTester, checkGradient) { + + auto optimizer = xacc::getService("gsl"); + + OptFunction f( + [](const std::vector &x, std::vector &grad) { + if (!grad.empty()) { + std::cout << "GRAD\n"; + grad[0] = 2. * x[0]; + } + auto xx = x[0] * x[0] + 5; + std::cout << xx << "\n"; + return xx; + }, + 1); + + EXPECT_EQ(1, f.dimensions()); + + optimizer->setOptions(HeterogeneousMap{ + std::make_pair("maxeval", 20), + std::make_pair("initial-parameters", std::vector{1.0}), + std::make_pair("optimizer", "bfgs")}); + + + auto result = optimizer->optimize(f); + + std::cout << result.first << " " << result.second[0] << "\n"; + + EXPECT_NEAR(result.first, 5.0, 1e-4); + EXPECT_NEAR(result.second[0], 0.0, 1e-4); +} + +TEST(ScipyOptimizerTester, checkGradientRosenbrock) { + + auto optimizer = xacc::getService("gsl"); + + OptFunction f( + [](const std::vector &x, std::vector &grad) { + if (!grad.empty()) { + // std::cout << "GRAD\n"; + grad[0] = -2 * (1 - x[0]) + 400 * (std::pow(x[0], 3) - x[1] * x[0]); + grad[1] = 200 * (x[1] - std::pow(x[0], 2)); + } + auto xx = + 100 * std::pow(x[1] - std::pow(x[0], 2), 2) + std::pow(1 - x[0], 2); + std::cout << xx << ", " << x << ", " << grad << "\n"; + + return xx; + }, + 2); + + EXPECT_EQ(2, f.dimensions()); + + optimizer->setOptions(HeterogeneousMap{std::make_pair("maxeval", 200), + std::make_pair("optimizer", "bfgs")}); + + auto result = optimizer->optimize(f); + + EXPECT_NEAR(result.first, 0.0, 1e-4); + EXPECT_NEAR(result.second[0], 1.0, 1e-4); + EXPECT_NEAR(result.second[1], 1.0, 1e-4); +} + +int main(int argc, char **argv) { + xacc::Initialize(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + auto ret = RUN_ALL_TESTS(); + xacc::Finalize(); + return ret; +} diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index 02db034d1..d72c4b2a3 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -120,3 +120,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_SYSTEM_NAME MATCHES set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() endif () + +if(XACC_BUILD_GSL) + add_subdirectory(gsl) +endif() \ No newline at end of file diff --git a/tpls/gsl/CMakeLists.txt b/tpls/gsl/CMakeLists.txt new file mode 100644 index 000000000..ad767832e --- /dev/null +++ b/tpls/gsl/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.0.0) +project(GSL) + +set(GSL_URL "https://mirror.fcix.net/gnu/gsl/gsl-latest.tar.gz" CACHE STRING "GSL download URL") + +set(DOWNLOAD_PATH "${CMAKE_SOURCE_DIR}/tpls/gsl/gsl.tar.gz") +set(EXTRACT_PATH "${CMAKE_SOURCE_DIR}/tpls/gsl/gsl") + +if(NOT EXISTS "${DOWNLOAD_PATH}") +file(DOWNLOAD ${GSL_URL} "${DOWNLOAD_PATH}.tmp" +STATUS download_status +LOG download_log +SHOW_PROGRESS +) + +list(GET download_status 0 download_status_code) +list(GET download_status 1 download_status_message) +if(download_status_code) + file(REMOVE "${DOWNLOAD_PATH}.tmp") + message(FATAL_ERROR "Download failed. Status: ${download_status_code} ${download_status_message}\nLog: ${download_log}") +endif() + +file(RENAME "${DOWNLOAD_PATH}.tmp" "${DOWNLOAD_PATH}") +endif() + +if(NOT IS_DIRECTORY "${EXTRACT_PATH}") +file(MAKE_DIRECTORY "${EXTRACT_PATH}.tmp") +execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xfv ${DOWNLOAD_PATH} + WORKING_DIRECTORY "${EXTRACT_PATH}.tmp" + OUTPUT_QUIET +) +file(RENAME "${EXTRACT_PATH}.tmp" "${EXTRACT_PATH}") +endif() + +file(GLOB download_gsl_root "${EXTRACT_PATH}/gsl-*") +if(download_gsl_root) + set(GSL_SOURCE "${download_gsl_root}" CACHE STRING "GSL location" FORCE) +endif() + +file(STRINGS "${GSL_SOURCE}/gsl_version.h" gsl_version_raw + REGEX "define GSL_VERSION " +) + +string(REGEX MATCH "([0-9]+\\.[0-9]+)" GSL_VERSION "${gsl_version_raw}") \ No newline at end of file From e7ed77d159af8de6feaab6e34180d3b386f86fb1 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 16 Jul 2024 18:06:29 +0000 Subject: [PATCH 039/101] Removed python stuff from QIREE build Signed-off-by: Daniel Claudino --- CMakeLists.txt | 56 +++++++++++++---------- quantum/plugins/CMakeLists.txt | 12 ++--- quantum/plugins/algorithms/CMakeLists.txt | 27 ++++++----- quantum/plugins/ibm/aer/CMakeLists.txt | 11 ++++- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57b9fb41a..b3519d592 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,37 +214,42 @@ endif() add_subdirectory(xacc) add_subdirectory(quantum) -find_package(Python COMPONENTS Interpreter Development) - -if(Python_FOUND) - if(${Python_VERSION} VERSION_GREATER_EQUAL 3.0.0) - message(STATUS "${BoldGreen}Found Python version ${Python_VERSION}. Building XACC Python API with ${Python_INCLUDE_DIRS}${ColorReset}") - add_subdirectory(python) - add_subdirectory(${CMAKE_SOURCE_DIR}/quantum/python) +# qiree doesn't need python, so we can ignore this and everything else that is python related +if(NOT QIREE_MINIMAL_BUILD) - # Double check we have module ipopo installed, contributes pelix - execute_process(COMMAND ${Python_EXECUTABLE} -c "import pelix" RESULT_VARIABLE PELIX_EXISTS) - - if(PELIX_EXISTS EQUAL "1") - # if not, check we have pip - execute_process(COMMAND ${Python_EXECUTABLE} -c "import pip" RESULT_VARIABLE PIP_EXISTS) +find_package(Python COMPONENTS Interpreter Development) - if(PIP_EXISTS EQUAL "0") - # we have pip, son just install ipopo - message(STATUS "${BoldGreen}Installing Pelix OSGi framework.${ColorReset}") - execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ipopo) + if(Python_FOUND) + if(${Python_VERSION} VERSION_GREATER_EQUAL 3.0.0) + message(STATUS "${BoldGreen}Found Python version ${Python_VERSION}. Building XACC Python API with ${Python_INCLUDE_DIRS}${ColorReset}") + add_subdirectory(python) + add_subdirectory(${CMAKE_SOURCE_DIR}/quantum/python) + + # Double check we have module ipopo installed, contributes pelix + execute_process(COMMAND ${Python_EXECUTABLE} -c "import pelix" RESULT_VARIABLE PELIX_EXISTS) + + if(PELIX_EXISTS EQUAL "1") + # if not, check we have pip + execute_process(COMMAND ${Python_EXECUTABLE} -c "import pip" RESULT_VARIABLE PIP_EXISTS) + + if(PIP_EXISTS EQUAL "0") + # we have pip, son just install ipopo + message(STATUS "${BoldGreen}Installing Pelix OSGi framework.${ColorReset}") + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ipopo) + else() + # we dont have pip, so warn the user + message(STATUS "${BoldYellow}Pelix Framework not found, but can't install via pip. Ensure you install ipopo module before using XACC Python API.${ColorReset}") + endif() else() - # we dont have pip, so warn the user - message(STATUS "${BoldYellow}Pelix Framework not found, but can't install via pip. Ensure you install ipopo module before using XACC Python API.${ColorReset}") + message(STATUS "${BoldGreen}Found Pelix framework.${ColorReset}") endif() else() - message(STATUS "${BoldGreen}Found Pelix framework.${ColorReset}") + message(STATUS "${BoldYellow}Found Python version ${Python_VERSION}. Version must be greater than 3.0.0, skipping Python API build.${ColorReset}") endif() else() - message(STATUS "${BoldYellow}Found Python version ${Python_VERSION}. Version must be greater than 3.0.0, skipping Python API build.${ColorReset}") + message(STATUS "${BoldYellow}Python interpreter or development headers not found. Skipping Python API build.${ColorReset}") endif() -else() - message(STATUS "${BoldYellow}Python interpreter or development headers not found. Skipping Python API build.${ColorReset}") + endif() # Version info @@ -269,7 +274,10 @@ install(DIRECTORY "${SPDLOG_INCLUDE_DIR}" DESTINATION include/spdlog/) install(DIRECTORY "${CMAKE_SOURCE_DIR}/tpls/exprtk" DESTINATION include) install(DIRECTORY "${EIGEN_INCLUDE_DIR}" DESTINATION include) install(DIRECTORY "${CMAKE_SOURCE_DIR}/tpls/rapidjson" DESTINATION include) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/tpls/pybind11" DESTINATION include) + +if(NOT QIREE_MINIMAL_BUILD) + install(DIRECTORY "${CMAKE_SOURCE_DIR}/tpls/pybind11" DESTINATION include) +endif() if(XACC_CPACK_DEB_PLATFORM) message(STATUS "CPack DEB Build Enabled.") diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index 4c2de7587..baec94747 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -31,14 +31,14 @@ add_subdirectory(optimal_control) add_subdirectory(qsim) add_subdirectory(atos_qlm) add_subdirectory(noise_model) -endif() find_library(QRACK_LIBRARY NAMES qrack) -if (QRACK_LIBRARY) - message("-- Found Qrack library (find_library(QRACK_LIBRARY NAMES qrack))") - add_subdirectory(qrack) -else() - message("-- Could NOT find Qrack library (missing: find_library(QRACK_LIBRARY NAMES qrack))") + if (QRACK_LIBRARY) + message("-- Found Qrack library (find_library(QRACK_LIBRARY NAMES qrack))") + add_subdirectory(qrack) + else() + message("-- Could NOT find Qrack library (missing: find_library(QRACK_LIBRARY NAMES qrack))") + endif() endif() if(XACC_BUILD_ANNEALING) diff --git a/quantum/plugins/algorithms/CMakeLists.txt b/quantum/plugins/algorithms/CMakeLists.txt index f813f3db7..3292eec20 100644 --- a/quantum/plugins/algorithms/CMakeLists.txt +++ b/quantum/plugins/algorithms/CMakeLists.txt @@ -11,21 +11,20 @@ # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ - if(NOT QIREE_MINIMAL_BUILD) -add_subdirectory(vqe) -add_subdirectory(rdm) -add_subdirectory(gradient_strategies) -add_subdirectory(qaoa) -add_subdirectory(rotoselect) -add_subdirectory(adapt) -add_subdirectory(qpe) -add_subdirectory(qpt) -add_subdirectory(ml) -add_subdirectory(qite) -add_subdirectory(qcmx) -add_subdirectory(qeom) -endif(QIREE_MINIMAL_BUILD) + add_subdirectory(vqe) + add_subdirectory(rdm) + add_subdirectory(gradient_strategies) + add_subdirectory(qaoa) + add_subdirectory(rotoselect) + add_subdirectory(adapt) + add_subdirectory(qpe) + add_subdirectory(qpt) + add_subdirectory(ml) + add_subdirectory(qite) + add_subdirectory(qcmx) + add_subdirectory(qeom) +endif(NOT QIREE_MINIMAL_BUILD) file(GLOB PYDECORATORS ${CMAKE_CURRENT_SOURCE_DIR}/vqe/python/*.py diff --git a/quantum/plugins/ibm/aer/CMakeLists.txt b/quantum/plugins/ibm/aer/CMakeLists.txt index d1a652504..9ed5cef96 100644 --- a/quantum/plugins/ibm/aer/CMakeLists.txt +++ b/quantum/plugins/ibm/aer/CMakeLists.txt @@ -1,6 +1,8 @@ set(LIBRARY_NAME xacc-aer) +if(NOT QIREE_MINIMAL_BUILD) add_subdirectory(py-aer) +endif() if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") if (NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") @@ -26,8 +28,15 @@ target_include_directories(${LIBRARY_NAME} target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate - xacc-py-aer-adapter ) + +if(NOT QIREE_MINIMAL_BUILD) + target_link_libraries(${LIBRARY_NAME} + PUBLIC xacc-py-aer-adapter + ) +endif(NOT QIREE_MINIMAL_BUILD) + + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") if(APPLE OR UNIX) if (NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") From de846909c480b3cda479be6f931d52dcf4797d1b Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Wed, 17 Jul 2024 21:07:09 +0000 Subject: [PATCH 040/101] Pulled latest NLOpt to fix Mac CI Signed-off-by: Daniel Claudino --- tpls/nlopt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/nlopt b/tpls/nlopt index 945d055b9..95172af2b 160000 --- a/tpls/nlopt +++ b/tpls/nlopt @@ -1 +1 @@ -Subproject commit 945d055b98be2db327f694b36ba507c41e1955fc +Subproject commit 95172af2b2ef8742c2da6deeedab5f4d9d919706 From 306db5fdacb473724b8d4fa93b2640e4f6962fb2 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 19 Jul 2024 08:53:30 -0400 Subject: [PATCH 041/101] Move external 'option' with other options --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 614136b66..226a18ce6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ else() endif() option(QIREE_MINIMAL_BUILD "Build only components for QIREE CI" OFF) +option(XACC_DEPS_EXTERNAL "Try find external dependencies (system installation) rather than tpls" OFF) if(QIREE_MINIMAL_BUILD) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQIREE_BUILD") @@ -182,7 +183,6 @@ ENDIF() find_package(LAPACK) # Dependencies: -option(XACC_DEPS_EXTERNAL "Try find external dependencies (system installation) rather than tpls" OFF) set(SPDLOG_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/spdlog/include/) if (XACC_DEPS_EXTERNAL) From c702a6eb98201d4c70856bddf49393895709fa78 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 19 Jul 2024 08:59:28 -0400 Subject: [PATCH 042/101] Fix nlopt submodule --- tpls/nlopt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tpls/nlopt b/tpls/nlopt index c2ffc4002..dc4ad82b6 160000 --- a/tpls/nlopt +++ b/tpls/nlopt @@ -1 +1 @@ -Subproject commit c2ffc40024d160a829f63ac6b5ab23c4abfe78ef +Subproject commit dc4ad82b6e374619efa423b585f7f96b875b2cb7 From 01c11aac70ac6d94d4a3764b8e79ca6bbf251520 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Wed, 24 Jul 2024 21:08:57 +0000 Subject: [PATCH 043/101] Updated HPC virtualization Signed-off-by: Daniel Claudino --- CMakeLists.txt | 4 +- .../hpc-virtualization/MPIProxy.cpp | 19 +- .../hpc-virtualization/MPIProxy.hpp | 50 ++++ .../hpc-virtualization/hpc_virt_decorator.cpp | 263 +++++++++++++++--- .../hpc-virtualization/hpc_virt_decorator.hpp | 35 ++- xacc/CMakeLists.txt | 20 +- xacc/xacc.cpp | 27 -- 7 files changed, 321 insertions(+), 97 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3519d592..fbc301e1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,9 @@ add_compile_flags_if_supported(-Wno-maybe-uninitialized) # Check MPI status # if MPI_CXX_COMPILER is not empty and XACC_ENABLE_MPI is set # turn MPI_ENABLED on -if(NOT MPI_CXX_COMPILER STREQUAL "" AND XACC_ENABLE_MPI) +# Update: we don't really need to give the compiler +# because if MPI is found, MPI_CXX_COMPILER is populated +if(XACC_ENABLE_MPI) find_package(MPI) if(MPI_FOUND) diff --git a/quantum/plugins/decorators/hpc-virtualization/MPIProxy.cpp b/quantum/plugins/decorators/hpc-virtualization/MPIProxy.cpp index 604ec2e17..c5013c24e 100644 --- a/quantum/plugins/decorators/hpc-virtualization/MPIProxy.cpp +++ b/quantum/plugins/decorators/hpc-virtualization/MPIProxy.cpp @@ -4,14 +4,25 @@ Copyright (C) 2018-2021 Dmitry I. Lyakh (Liakh) Copyright (C) 2018-2021 Oak Ridge National Laboratory (UT-Battelle) **/ #include "MPIProxy.hpp" - -#include "mpi.h" - #include - #include #include +template <> +MPI_Datatype MPIDataTypeResolver::getMPIDatatype() { + return MPI_INT; +} + +template <> +MPI_Datatype MPIDataTypeResolver::getMPIDatatype() { + return MPI_DOUBLE; +} + +template <> +MPI_Datatype MPIDataTypeResolver::getMPIDatatype() { + return MPI_CHAR; +} + namespace xacc { //Temporary buffers: diff --git a/quantum/plugins/decorators/hpc-virtualization/MPIProxy.hpp b/quantum/plugins/decorators/hpc-virtualization/MPIProxy.hpp index eaffa06ff..5cbb6889e 100644 --- a/quantum/plugins/decorators/hpc-virtualization/MPIProxy.hpp +++ b/quantum/plugins/decorators/hpc-virtualization/MPIProxy.hpp @@ -9,6 +9,13 @@ Copyright (C) 2018-2021 Oak Ridge National Laboratory (UT-Battelle) **/ #include #include #include +#include "mpi.h" + +template +class MPIDataTypeResolver { +public: + MPI_Datatype getMPIDatatype(); +}; namespace xacc { @@ -142,6 +149,49 @@ class ProcessGroup { different MPI processes, thus putting them into disjoint subgroups. **/ std::shared_ptr split(int my_subgroup) const; + + // some useful wrappers + + // I could move this to a single function, but don't + // want to abuse template specialization here + // this broadcasts a single element (int/char/double) + template + void broadcast(T element) { + + MPIDataTypeResolver resolver; + MPI_Datatype mpiType = resolver.getMPIDatatype(); + MPI_Bcast(&element, 1, mpiType, 0, + this->getMPICommProxy().getRef()); + } + + // this broadcasts a vector + template + void broadcast(std::vector &vec) { + + MPIDataTypeResolver resolver; + MPI_Datatype mpiType = resolver.getMPIDatatype(); + MPI_Bcast(vec.data(), vec.size(), mpiType, 0, + this->getMPICommProxy().getRef()); + }; + + + // this Allgatherv's the content of local vectors + // into a global vector + template + void allGatherv(std::vector &local, + std::vector &global, + std::vector &nLocalData, + std::vector &shift) { + + MPIDataTypeResolver resolver; + MPI_Datatype mpiType = resolver.getMPIDatatype(); + MPI_Allgatherv(local.data(), local.size(), mpiType, + global.data(), nLocalData.data(), + shift.data(), mpiType, + this->getMPICommProxy().getRef()); + + } + protected: std::vector process_ranks_; //global ranks of the MPI processes forming the process group diff --git a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp index 92c896e13..915ee5257 100644 --- a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp +++ b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp @@ -14,13 +14,32 @@ #include "hpc_virt_decorator.hpp" #include "InstructionIterator.hpp" #include "Utils.hpp" -#include "xacc.hpp" +#include "xacc_service.hpp" +#include "TearDown.hpp" #include +namespace { +static bool hpcVirtDecoratorInitializedMpi = false; +} + namespace xacc { namespace quantum { void HPCVirtDecorator::initialize(const HeterogeneousMap ¶ms) { + + if (!qpuComm) { + // Initializing MPI here + int provided, isMPIInitialized; + MPI_Initialized(&isMPIInitialized); + if (!isMPIInitialized) { + MPI_Init_thread(0, NULL, MPI_THREAD_MULTIPLE, &provided); + hpcVirtDecoratorInitializedMpi = true; + if (provided != MPI_THREAD_MULTIPLE) { + xacc::warning("MPI_THREAD_MULTIPLE not provided."); + } + } + } + decoratedAccelerator->initialize(params); if (params.keyExists("n-virtual-qpus")) { @@ -34,6 +53,29 @@ void HPCVirtDecorator::initialize(const HeterogeneousMap ¶ms) { } n_virtual_qpus = params.get("n-virtual-qpus"); } + + shots = -1; + if (params.keyExists("shots")) { + shots = params.get("shots"); + if (shots < 1) { + xacc::error("Invalid 'shots' parameter."); + } + } + + isVqeMode = false; + if (params.keyExists("vqe-mode")) { + isVqeMode = params.get("vqe-mode"); + } else { + isVqeMode = (shots < 1); + } + + if (shots >= 1 && isVqeMode || shots < 1 && !isVqeMode) { + xacc::error("Please choose between shot-based simulation or VQE mode."); + } else if (shots >= 1) { + xacc::info("Running shot-based simulation."); + } else { + xacc::info("Enable VQE mode."); + } } void HPCVirtDecorator::updateConfiguration(const HeterogeneousMap &config) { @@ -64,6 +106,7 @@ void HPCVirtDecorator::execute( // their quantum execution across the node sub-groups. // Get the rank and size in the original communicator + auto start = std::chrono::high_resolution_clock::now(); int world_size, world_rank; MPI_Comm_size(MPI_COMM_WORLD, &world_size); MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); @@ -109,8 +152,14 @@ void HPCVirtDecorator::execute( // Give that sub communicator to the accelerator void *qpu_comm_ptr = reinterpret_cast(qpuComm->getMPICommProxy().getRef()); - decoratedAccelerator->updateConfiguration( - {{"mpi-communicator", qpu_comm_ptr}}); + + // this enables shot-based simulation + HeterogeneousMap properties; + properties.insert("mpi-communicator", qpu_comm_ptr); + if (!isVqeMode) { + properties.insert("shots", shots); + } + decoratedAccelerator->updateConfiguration(properties); // get the number of sub-communicators // Everybody split the CompositeInstructions vector into n_virtual_qpu @@ -146,16 +195,22 @@ void HPCVirtDecorator::execute( } // broadcast the total number of children - MPI_Bcast(&nGlobalChildren, 1, MPI_INT, 0, - qpuComm->getMPICommProxy().getRef()); + qpuComm->broadcast(nGlobalChildren); // broadcast the number of children in each communicator - MPI_Bcast(nLocalChildren.data(), nLocalChildren.size(), MPI_INT, 0, - qpuComm->getMPICommProxy().getRef()); + qpuComm->broadcast(nLocalChildren); - // get expectation values and the size of the key of each child buffer - std::vector globalExpVals(nGlobalChildren); + // get expectation values/bitstrings and the size of the key of each child + // buffer std::vector globalKeySizes(nGlobalChildren); + std::vector globalNumberBitStrings; + std::vector globalExpVals; + if (isVqeMode) { + globalExpVals.resize(nGlobalChildren); + } else { + globalNumberBitStrings.resize(nGlobalChildren); + } + if (world_rank == qpuComm->getProcessRanks()[0]) { // get displacements for the keys in each comm @@ -167,47 +222,85 @@ void HPCVirtDecorator::execute( // get size of each key in the communicator std::vector localExpVals; - std::vector localKeySizes; + std::vector localKeySizes, localNumberBitStrings; for (auto child : my_buffer->getChildren()) { localKeySizes.push_back(child->name().size()); - localExpVals.push_back(child->getExpectationValueZ()); - } - // gather all expectation values - MPI_Allgatherv(localExpVals.data(), localExpVals.size(), MPI_DOUBLE, - globalExpVals.data(), nLocalChildren.data(), - nKeyShift.data(), MPI_DOUBLE, - zeroRanksComm->getMPICommProxy().getRef()); + if (isVqeMode) { + localExpVals.push_back(child->getExpectationValueZ()); + } else { + localNumberBitStrings.push_back(child->getMeasurementCounts().size()); + } + } // gather the size of each child key - MPI_Allgatherv(localKeySizes.data(), localKeySizes.size(), MPI_INT, - globalKeySizes.data(), nLocalChildren.data(), - nKeyShift.data(), MPI_INT, - zeroRanksComm->getMPICommProxy().getRef()); + zeroRanksComm->allGatherv(localKeySizes, globalKeySizes, nLocalChildren, + nKeyShift); + + if (isVqeMode) { + // gather all expectation values + zeroRanksComm->allGatherv(localExpVals, globalExpVals, nLocalChildren, + nKeyShift); + } else { + // gather all bitstrings + zeroRanksComm->allGatherv(localNumberBitStrings, globalNumberBitStrings, + nLocalChildren, nKeyShift); + } } - // broadcast expectation values - MPI_Bcast(globalExpVals.data(), globalExpVals.size(), MPI_DOUBLE, 0, - qpuComm->getMPICommProxy().getRef()); - // broadcast size of each key - MPI_Bcast(globalKeySizes.data(), globalKeySizes.size(), MPI_INT, 0, - qpuComm->getMPICommProxy().getRef()); + qpuComm->broadcast(globalKeySizes); + + // broadcast results + if (isVqeMode) { + // broadcast expectation values + qpuComm->broadcast(globalExpVals); + } else { + // broadcast number of bit strings + qpuComm->broadcast(globalNumberBitStrings); + } // get the size of all keys auto nGlobalKeyChars = std::accumulate(globalKeySizes.begin(), globalKeySizes.end(), 0); + // get total number of measured bitstrings + auto nGlobalBitStrings = std::accumulate(globalNumberBitStrings.begin(), + globalNumberBitStrings.end(), 0); + // gather all keys chars std::vector globalKeyChars(nGlobalKeyChars); + std::vector globalBitStrings, globalCounts; + if (!isVqeMode) { + globalBitStrings.resize(nGlobalBitStrings); + globalCounts.resize(nGlobalBitStrings); + } if (world_rank == qpuComm->getProcessRanks()[0]) { // get local key char arrays + // and local bitstrings and counts std::vector localKeys; + std::vector localBitStringIndices, localCounts; for (auto child : my_buffer->getChildren()) { + for (auto c : child->name()) { localKeys.push_back(c); } + + // get bitstring decimals and counts + if (!isVqeMode) { + for (auto &count : child->getMeasurementCounts()) { + auto bitString = count.first; + // stoi is MSB + if (decoratedAccelerator->getBitOrder() == + Accelerator::BitOrder::LSB) { + std::reverse(bitString.begin(), bitString.end()); + } + auto index = std::stoi(count.first, nullptr, 2); + localBitStringIndices.push_back(index); + localCounts.push_back(count.second); + } + } } // get the size of keys in the communicator @@ -227,18 +320,58 @@ void HPCVirtDecorator::execute( } // gather all key chars - MPI_Allgatherv(localKeys.data(), localKeys.size(), MPI_CHAR, - globalKeyChars.data(), commKeySize.data(), - keySizeShift.data(), MPI_CHAR, - zeroRanksComm->getMPICommProxy().getRef()); + zeroRanksComm->allGatherv(localKeys, globalKeyChars, commKeySize, + keySizeShift); + + if (!isVqeMode) { + + // get number of bit strings in the communicator + std::vector commNumberBitStrings(n_virtual_qpus); + shift = 0; + for (int i = 0; i < n_virtual_qpus; i++) { + auto it = globalNumberBitStrings.begin() + shift; + commNumberBitStrings[i] = + std::accumulate(it, it + nLocalChildren[i], 0); + shift += nLocalChildren[i]; + } + + // shifts for bit strings + std::vector bitStringShift(n_virtual_qpus); + for (int i = 1; i < n_virtual_qpus; i++) { + bitStringShift[i] = std::accumulate( + commNumberBitStrings.begin(), commNumberBitStrings.begin() + i, 0); + } + + // gather all bit strings + zeroRanksComm->allGatherv(localBitStringIndices, globalBitStrings, + commNumberBitStrings, bitStringShift); + // gather all counts + zeroRanksComm->allGatherv(localCounts, globalCounts, commNumberBitStrings, + bitStringShift); + } } // broadcast all keys - MPI_Bcast(globalKeyChars.data(), globalKeyChars.size(), MPI_CHAR, 0, - qpuComm->getMPICommProxy().getRef()); + qpuComm->broadcast(globalKeyChars); + + if (!isVqeMode) { + // broadcast indices + qpuComm->broadcast(globalBitStrings); + qpuComm->broadcast(globalCounts); + } + + // get binary from decimal + const auto getBinary = [=](int decimal) { + std::string s; + do { + s += (decimal % 2 == 0 ? "0" : "1"); + decimal /= 2; + } while (decimal != 0); + return s; + }; // now every process has everything to rebuild the buffer - int shift = 0; + int shift = 0, countShift = 0; for (int i = 0; i < nGlobalChildren; i++) { // get child name @@ -248,7 +381,33 @@ void HPCVirtDecorator::execute( // create child buffer and append it to buffer auto child = xacc::qalloc(buffer->size()); child->setName(name); - child->addExtraInfo("exp-val-z", globalExpVals[i]); + + if (isVqeMode) { + + child->addExtraInfo("exp-val-z", globalExpVals[i]); + + } else { + + auto nChildBitStrings = globalNumberBitStrings[i]; + for (int b = 0; b < nChildBitStrings; b++) { + + auto counts = globalCounts[b + countShift]; + auto bitStringDecimal = globalBitStrings[b + countShift]; + auto bitString = getBinary(bitStringDecimal); + // check if we need to pad zeros + auto nMeasuredBits = + std::count_if(name.begin(), name.end(), [](char c) { + return std::string("XYZ").find(c) != std::string::npos; + }); + if (nMeasuredBits > bitString.size()) { + bitString += std::string(nMeasuredBits - bitString.size(), '0'); + } + std::reverse(bitString.begin(), bitString.end()); + child->appendMeasurement(bitString, counts); + } + countShift += nChildBitStrings; + } + buffer->appendChild(name, child); shift += globalKeySizes[i]; } @@ -261,6 +420,38 @@ void HPCVirtDecorator::execute( return; } +void HPCVirtDecorator::finalize() { + if (qpuComm) { + // Make sure we explicitly release this so that MPICommProxy is destroyed + // before framework shutdown (MPI_Finalize if needed) + qpuComm.reset(); + } +} + +class HPCVirtTearDown : public xacc::TearDown { +public: + virtual void tearDown() override { + auto c = xacc::getService("hpc-virtualization", + false); + if (c) { + auto casted = + std::dynamic_pointer_cast(c); + assert(casted); + casted->finalize(); + } + + int finalized, initialized; + MPI_Initialized(&initialized); + if (initialized) { + MPI_Finalized(&finalized); + if (!finalized && hpcVirtDecoratorInitializedMpi) { + MPI_Finalize(); + } + } + } + virtual std::string name() const override { return "xacc-hpc-virt"; } +}; + } // namespace quantum } // namespace xacc @@ -282,6 +473,8 @@ class US_ABI_LOCAL HPCVirtActivator : public BundleActivator { context.RegisterService(c); context.RegisterService(c); + context.RegisterService( + std::make_shared()); } /** diff --git a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.hpp b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.hpp index 691597b90..4a12fd811 100644 --- a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.hpp +++ b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.hpp @@ -14,7 +14,6 @@ #ifndef XACC_HPC_VIRT_DECORATOR_HPP_ #define XACC_HPC_VIRT_DECORATOR_HPP_ -#include "mpi.h" #include "xacc.hpp" #include "MPIProxy.hpp" #include "AcceleratorDecorator.hpp" @@ -26,7 +25,8 @@ namespace quantum { class HPCVirtDecorator : public AcceleratorDecorator { protected: - int n_virtual_qpus = 1; + bool isVqeMode; + int n_virtual_qpus = 1, shots; // The MPI communicator for each QPU std::shared_ptr qpuComm; @@ -45,31 +45,30 @@ class HPCVirtDecorator : public AcceleratorDecorator { const std::string name() const override { return "hpc-virtualization"; } const std::string description() const override { return ""; } + void finalize(); - ~HPCVirtDecorator() override { } + ~HPCVirtDecorator() override { }; private: - template - std::vector> split_vector(const std::vector &vec, - size_t n) { - std::vector> outVec; - size_t length = vec.size() / n; - size_t remain = vec.size() % n; +template +std::vector> split_vector(const std::vector& inputVector, size_t numSegments) { + std::vector> result; - size_t begin = 0; - size_t end = 0; + size_t inputSize = inputVector.size(); + size_t segmentSize = (inputSize + numSegments - 1) / numSegments; // Ceiling division - for (size_t i = 0; i < std::min(n, vec.size()); ++i) { - end += (remain > 0) ? (length + !!(remain--)) : length; + auto begin = inputVector.begin(); + auto end = inputVector.end(); - outVec.push_back(std::vector(vec.begin() + begin, vec.begin() + end)); - - begin = end; + for (size_t i = 0; i < numSegments; ++i) { + auto segmentEnd = std::next(begin, std::min(segmentSize, static_cast(std::distance(begin, end)))); + result.emplace_back(begin, segmentEnd); + begin = segmentEnd; } - return outVec; - } + return result; +} }; } // namespace quantum diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index 40f827085..d6cdbe1ff 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -85,17 +85,14 @@ message( ${NLOHMANN_INCLUDE_DIR} ${SPDLOG_INCLUDE_DIR}) - # linking against MPI libraries found by cmake - if(MPI_FOUND) - target_link_libraries(xacc - PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES} - PRIVATE cpr ${LIBUNWIND_LIBRARIES} - ${LIBUNWINDX86_LIBRARIES}) - else() - target_link_libraries(xacc + target_link_libraries(xacc PUBLIC CppMicroServices - PRIVATE cpr ${LIBUNWIND_LIBRARIES} + PRIVATE cpr + ${LIBUNWIND_LIBRARIES} ${LIBUNWINDX86_LIBRARIES}) + # linking against MPI libraries found by cmake + if(MPI_FOUND) + target_link_libraries(xacc PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES}) endif() else() @@ -119,11 +116,10 @@ else() ${NLOHMANN_INCLUDE_DIR} ${SPDLOG_INCLUDE_DIR}) + target_link_libraries(xacc PUBLIC CppMicroServices PRIVATE cpr) # linking against MPI libraries found by cmake if(MPI_FOUND) - target_link_libraries(xacc PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES} PRIVATE cpr) - else() - target_link_libraries(xacc PUBLIC CppMicroServices PRIVATE cpr) + target_link_libraries(xacc PUBLIC ${MPI_CXX_LIBRARIES}) endif() endif() diff --git a/xacc/xacc.cpp b/xacc/xacc.cpp index 89a9cabce..c67fa1b7c 100644 --- a/xacc/xacc.cpp +++ b/xacc/xacc.cpp @@ -30,10 +30,6 @@ #include #include "TearDown.hpp" -#ifdef MPI_ENABLED -#include "mpi.h" -#endif - using namespace cxxopts; namespace xacc { @@ -51,11 +47,6 @@ std::map> std::map> allocated_buffers{}; std::string rootPathString = ""; - -#ifdef MPI_ENABLED -int isMPIInitialized; -#endif - void set_verbose(bool v) { verbose = v; } int getArgc() { return argc; } @@ -116,18 +107,6 @@ void Initialize(int arc, char **arv) { XACCLogger::instance()->dumpQueue(); } - // Initializing MPI here -#ifdef MPI_ENABLED - int provided; - MPI_Initialized(&isMPIInitialized); - if (!isMPIInitialized) { - MPI_Init_thread(0, NULL, MPI_THREAD_MULTIPLE, &provided); - if (provided != MPI_THREAD_MULTIPLE) { - xacc::warning("MPI_THREAD_MULTIPLE not provided."); - } - isMPIInitialized = 1; - } -#endif } void setIsPyApi() { isPyApi = true; } @@ -869,12 +848,6 @@ void Finalize() { compilation_database.clear(); allocated_buffers.clear(); xacc::ServiceAPI_Finalize(); - // This replaces the HPC virtualization TearDown -#ifdef MPI_ENABLED - if (isMPIInitialized) { - MPI_Finalize(); - } -#endif } } From ec7b05020c1e67fd291c6a3df42c2d2ed4a6c13a Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 25 Jul 2024 17:23:32 +0000 Subject: [PATCH 044/101] HPC virtualization clean-up Signed-off-by: Daniel Claudino --- CMakeLists.txt | 2 +- .../decorators/hpc-virtualization/hpc_virt_decorator.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc301e1a..add9b84a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,7 @@ add_compile_flags_if_supported(-Wno-maybe-uninitialized) # Check MPI status # if MPI_CXX_COMPILER is not empty and XACC_ENABLE_MPI is set # turn MPI_ENABLED on -# Update: we don't really need to give the compiler +# Update: we don't really need to give the path to the compiler # because if MPI is found, MPI_CXX_COMPILER is populated if(XACC_ENABLE_MPI) find_package(MPI) diff --git a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp index 915ee5257..dd123d737 100644 --- a/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp +++ b/quantum/plugins/decorators/hpc-virtualization/hpc_virt_decorator.cpp @@ -106,7 +106,6 @@ void HPCVirtDecorator::execute( // their quantum execution across the node sub-groups. // Get the rank and size in the original communicator - auto start = std::chrono::high_resolution_clock::now(); int world_size, world_rank; MPI_Comm_size(MPI_COMM_WORLD, &world_size); MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); From 05752733b6ae9b1076aa27f05e56f8eeaaa22137 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 29 Jul 2024 10:55:14 -0400 Subject: [PATCH 045/101] Use targets for spdlog to fix "external fmt" error --- CMakeLists.txt | 18 +++++++++--------- xacc/CMakeLists.txt | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 226a18ce6..f5e5bdc0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,17 +184,17 @@ find_package(LAPACK) # Dependencies: -set(SPDLOG_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/spdlog/include/) + if (XACC_DEPS_EXTERNAL) find_package(spdlog) - if (spdlog_FOUND) - get_target_property(SPDLOG_TARGET_INC_DIR spdlog::spdlog_header_only INTERFACE_INCLUDE_DIRECTORIES) - if (EXISTS ${SPDLOG_TARGET_INC_DIR}/spdlog/spdlog.h) - # Found a seemingly valid spdlog installation, use it when XACC_DEPS_EXTERNAL is set - message(STATUS "${BoldGreen}spdlog: Found system installation at ${SPDLOG_TARGET_INC_DIR}/spdlog${ColorReset}") - set(SPDLOG_INCLUDE_DIR "${SPDLOG_TARGET_INC_DIR}") - endif() - endif() +endif() +if(NOT spdlog_FOUND) + # Create an interface target to the vendored spdlog + set(SPDLOG_INCLUDE_DIR "${SPDLOG_TARGET_INC_DIR}") + add_library(spdlog::spdlog INTERFACE IMPORTED) + target_include_directories(spdlog::spdlog INTERFACE + "${PROJECT_SOURCE_DIR}/tpls/spdlog/include" + ) endif() set(NLOHMANN_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/nlohmann/single_include) diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index b36b01f72..0dba463f6 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -64,6 +64,8 @@ message( target_link_libraries(xacc PRIVATE ${LIBUNWIND_LIBRARIES} ${LIBUNWINDX86_LIBRARIES} + PUBLIC + spdlog::spdlog ) endif() @@ -86,7 +88,6 @@ target_include_directories(xacc optimizer ${CMAKE_SOURCE_DIR}/tpls/mpark-variant ${NLOHMANN_INCLUDE_DIR} - ${SPDLOG_INCLUDE_DIR} ) target_link_libraries(xacc PUBLIC From 887a02187c11fc18f99766bac14bc17c1a78c205 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 29 Jul 2024 10:55:32 -0400 Subject: [PATCH 046/101] Add build/install to gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 56a122735..b78330eff 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ *.out *.app /build/ +/build-*/ +/install/ +/install-*/ /plugins/ /.cproject /.project @@ -49,4 +52,4 @@ compile_commands.json .vscode/* .theia/* # Python test cache -__pycache__/ \ No newline at end of file +__pycache__/ From 0a6cda4accf639ee615149a38ba90bd821d2307c Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 29 Jul 2024 18:56:44 +0000 Subject: [PATCH 047/101] Added option to disable remote accelerators Signed-off-by: Daniel Claudino --- CMakeLists.txt | 49 ++++--- quantum/plugins/CMakeLists.txt | 36 +++-- quantum/plugins/ibm/CMakeLists.txt | 35 ++--- quantum/plugins/ibm/IBMActivator.cpp | 8 +- .../ibm/accelerator/IBMAccelerator.cpp | 14 +- quantum/plugins/rigetti/CMakeLists.txt | 6 +- xacc/CMakeLists.txt | 135 ++++++++---------- xacc/xacc.cpp | 3 + xacc/xacc.hpp | 6 +- 9 files changed, 153 insertions(+), 139 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index add9b84a3..4ad4f12cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,12 +16,32 @@ set(CMAKE_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 17) message(STATUS "C++ version ${CXX_STANDARD} configured.") +if(NOT WIN32) + string(ASCII 27 Esc) + set(ColorReset "${Esc}[m") + set(ColorBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() + option(XACC_BUILD_TESTS "Build test programs" OFF) option(XACC_BUILD_EXAMPLES "Build example programs" OFF) option(XACC_ENSMALLEN_INCLUDE_DIR "Path to ensmallen.hpp for mlpack optimizer" "") option(XACC_ARMADILLO_INCLUDE_DIR "Path to armadillo header for mlpack optimizer" "") -option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) option(XACC_BUILD_SCIPY "Build Scipy optimizer plugin" OFF) +option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) if(XACC_BUILD_ANNEALING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") else() @@ -29,11 +49,16 @@ else() endif() option(QIREE_MINIMAL_BUILD "Build only components for QIREE CI" OFF) - if(QIREE_MINIMAL_BUILD) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQIREE_BUILD") endif() +option(XACC_REMOTE_ACCELERATORS "Build remove (cloud) accelerators" ON) +if(NOT XACC_REMOTE_ACCELERATORS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DREMOTE_DISABLED") + message(STATUS "${BoldYellow}Skipping remote accelerators. Only local simulators are now enabled.{ColorReset}") +endif() + if(FROM_SETUP_PY AND NOT APPLE) message(STATUS "Running build from setup.py, linking to static libstdc++") set(CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++" CACHE INTERNAL "" FORCE) @@ -92,26 +117,6 @@ include(format) include(cxxFlags) include(ExternalProject) -if(NOT WIN32) - string(ASCII 27 Esc) - set(ColorReset "${Esc}[m") - set(ColorBold "${Esc}[1m") - set(Red "${Esc}[31m") - set(Green "${Esc}[32m") - set(Yellow "${Esc}[33m") - set(Blue "${Esc}[34m") - set(Magenta "${Esc}[35m") - set(Cyan "${Esc}[36m") - set(White "${Esc}[37m") - set(BoldRed "${Esc}[1;31m") - set(BoldGreen "${Esc}[1;32m") - set(BoldYellow "${Esc}[1;33m") - set(BoldBlue "${Esc}[1;34m") - set(BoldMagenta "${Esc}[1;35m") - set(BoldCyan "${Esc}[1;36m") - set(BoldWhite "${Esc}[1;37m") -endif() - if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.xacc" CACHE PATH "default install path" FORCE) endif() diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index baec94747..38cc06d65 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -12,27 +12,33 @@ # *******************************************************************************/ add_subdirectory(ibm) add_subdirectory(algorithms) -add_subdirectory(ionq) add_subdirectory(xasm) add_subdirectory(qpp) add_subdirectory(staq) -add_subdirectory(honeywell) + +if(XACC_REMOTE_ACCELERATORS) + add_subdirectory(ionq) + add_subdirectory(honeywell) +endif() if(NOT QIREE_MINIMAL_BUILD) -add_subdirectory(placement) -add_subdirectory(iontrap) -add_subdirectory(circuits) -add_subdirectory(optimizers) -add_subdirectory(circuit_optimizers) -add_subdirectory(rigetti) -add_subdirectory(decorators) -add_subdirectory(observable_transforms) -add_subdirectory(optimal_control) -add_subdirectory(qsim) -add_subdirectory(atos_qlm) -add_subdirectory(noise_model) + add_subdirectory(placement) + add_subdirectory(iontrap) + add_subdirectory(circuits) + add_subdirectory(optimizers) + add_subdirectory(circuit_optimizers) + add_subdirectory(decorators) + add_subdirectory(observable_transforms) + add_subdirectory(optimal_control) + add_subdirectory(qsim) + add_subdirectory(noise_model) + add_subdirectory(rigetti) + + if(XACC_REMOTE_ACCELERATORS) + add_subdirectory(atos_qlm) + endif() -find_library(QRACK_LIBRARY NAMES qrack) + find_library(QRACK_LIBRARY NAMES qrack) if (QRACK_LIBRARY) message("-- Found Qrack library (find_library(QRACK_LIBRARY NAMES qrack))") add_subdirectory(qrack) diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index fa1674093..b13660b0b 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -28,28 +28,29 @@ file(GLOB SRC compiler/generated/*.cpp accelerator/OpenPulseVisitor.cpp) - usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC) usfunctiongeneratebundleinit(TARGET ${LIBRARY_NAME} OUT SRC) add_library(${LIBRARY_NAME} SHARED ${SRC}) - target_include_directories(${LIBRARY_NAME} - PUBLIC accelerator - compiler - common - compiler/generated - accelerator/json - ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src - ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include) - #${CMAKE_SOURCE_DIR}/tpls/exprtk - - target_link_libraries(${LIBRARY_NAME} - PUBLIC xacc - xacc-quantum-gate - ${ANTLR_LIB} - CppMicroServices PRIVATE cpr) +target_include_directories(${LIBRARY_NAME} + PUBLIC accelerator + compiler + common + compiler/generated + accelerator/json + ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src + ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include) + +target_link_libraries(${LIBRARY_NAME} + PUBLIC xacc + xacc-quantum-gate + ${ANTLR_LIB} + CppMicroServices) +if(XACC_REMOTE_ACCELERATORS) + target_link_libraries(${LIBRARY_NAME} PRIVATE cpr) +endif() set(_bundle_name xacc_ibm) set_target_properties(${LIBRARY_NAME} @@ -81,4 +82,4 @@ if(XACC_BUILD_TESTS) add_subdirectory(accelerator/json/tests) endif() -install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) +install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) \ No newline at end of file diff --git a/quantum/plugins/ibm/IBMActivator.cpp b/quantum/plugins/ibm/IBMActivator.cpp index 79672703e..2f72b5104 100644 --- a/quantum/plugins/ibm/IBMActivator.cpp +++ b/quantum/plugins/ibm/IBMActivator.cpp @@ -39,7 +39,13 @@ class US_ABI_LOCAL IBMActivator : public BundleActivator { /** */ void Start(BundleContext context) { + +//# +//ifndef REMOTE_DISABLED auto acc = std::make_shared(); + context.RegisterService(acc); +//# +//endif #ifdef LAPACK_FOUND auto acc2 = std::make_shared(); @@ -52,8 +58,6 @@ class US_ABI_LOCAL IBMActivator : public BundleActivator { auto c2 = std::make_shared(); context.RegisterService(c2); - context.RegisterService(acc); - auto qasm_qobj_gen = std::make_shared(); auto pulse_qobj_gen = std::make_shared(); diff --git a/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp b/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp index a3fa5942c..ac8c50791 100644 --- a/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp +++ b/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp @@ -19,7 +19,9 @@ #include "OpenPulseVisitor.hpp" #include "CountGatesOfTypeVisitor.hpp" +#ifndef REMOTE_DISABLED #include +#endif #include "xacc.hpp" #include "xacc_service.hpp" @@ -1085,7 +1087,7 @@ const std::string RestClient::post(const std::string &remoteUrl, const std::string &path, const std::string &postStr, std::map headers) { - +#ifndef REMOTE_DISABLED if (headers.empty()) { headers.insert(std::make_pair("Content-type", "application/json")); headers.insert(std::make_pair("Connection", "keep-alive")); @@ -1109,10 +1111,14 @@ const std::string RestClient::post(const std::string &remoteUrl, r.error.message + ": " + r.text); return r.text; +#else + return ""; +#endif } void RestClient::put(const std::string &remoteUrl, const std::string &putStr, std::map headers) { +#ifndef REMOTE_DISABLED if (headers.empty()) { headers.insert(std::make_pair("Content-type", "application/json")); headers.insert(std::make_pair("Connection", "keep-alive")); @@ -1133,12 +1139,14 @@ void RestClient::put(const std::string &remoteUrl, const std::string &putStr, throw std::runtime_error("HTTP POST Error - status code " + std::to_string(r.status_code) + ": " + r.error.message + ": " + r.text); +#endif return; } const std::string RestClient::get(const std::string &remoteUrl, const std::string &path, std::map headers, std::map extraParams) { +#ifndef REMOTE_DISABLED if (headers.empty()) { headers.insert(std::make_pair("Content-type", "application/json")); headers.insert(std::make_pair("Connection", "keep-alive")); @@ -1166,6 +1174,9 @@ RestClient::get(const std::string &remoteUrl, const std::string &path, r.error.message + ": " + r.text); return r.text; +#else + return ""; +#endif } std::string IBMAccelerator::post(const std::string &_url, @@ -1424,6 +1435,7 @@ void IBMPulseTransform::apply(std::shared_ptr program, program->clear(); program->addInstructions(loweredKernel->getInstructions()); } + } // namespace quantum } // namespace xacc diff --git a/quantum/plugins/rigetti/CMakeLists.txt b/quantum/plugins/rigetti/CMakeLists.txt index 1ea4aac30..332873f95 100644 --- a/quantum/plugins/rigetti/CMakeLists.txt +++ b/quantum/plugins/rigetti/CMakeLists.txt @@ -70,5 +70,7 @@ endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) -add_subdirectory(qcs) -add_subdirectory(quilc) \ No newline at end of file +if(XACC_REMOTE_ACCELERATORS) + add_subdirectory(qcs) + add_subdirectory(quilc) +endif() \ No newline at end of file diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index d6cdbe1ff..0c6b20023 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -30,98 +30,75 @@ file(GLOB ir/*.hpp compiler/Compiler.hpp accelerator/*.hpp - accelerator/remote/*.hpp utils/*.hpp service/*.hpp algorithm/*.hpp optimizer/*.hpp) -add_library(xacc SHARED - xacc.cpp - accelerator/AcceleratorBuffer.cpp - utils/Utils.cpp - utils/CLIParser.cpp - utils/heterogeneous.cpp - ir/IRBuilder.cpp - service/ServiceRegistry.cpp - service/xacc_service.cpp - accelerator/remote/RemoteAccelerator.cpp) - -if (XACC_USE_EXTERNAL_CPR) - # External CPR must be accompanied by CURL. - find_package(CURL REQUIRED) - set_target_properties(xacc PROPERTIES - INTERFACE_LINK_LIBRARIES "CURL::libcurl" - ) -else() - add_dependencies(xacc cpr) +file(GLOB SOURCES + xacc.cpp + accelerator/AcceleratorBuffer.cpp + utils/Utils.cpp + utils/CLIParser.cpp + utils/heterogeneous.cpp + ir/IRBuilder.cpp + service/ServiceRegistry.cpp + service/xacc_service.cpp) + +if(XACC_REMOTE_ACCELERATORS) + list(APPEND HEADERS accelerator/remote/RemoteAccelerator.hpp) + list(APPEND SOURCES accelerator/remote/RemoteAccelerator.cpp) endif() -if(MPI_FOUND) - include_directories(${MPI_CXX_HEADER_DIR}) +add_library(xacc SHARED ${SOURCES}) + +if(XACC_REMOTE_ACCELERATORS) + if (XACC_USE_EXTERNAL_CPR) + # External CPR must be accompanied by CURL. + find_package(CURL REQUIRED) + set_target_properties(xacc PROPERTIES + INTERFACE_LINK_LIBRARIES "CURL::libcurl" + ) + else() + add_dependencies(xacc cpr) + endif() endif() +target_include_directories(xacc +PRIVATE ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include + ${CMAKE_SOURCE_DIR}/tpls/cxxopts +PUBLIC . + ir + compiler + program + accelerator + utils + service + algorithm + optimizer + ${CMAKE_SOURCE_DIR}/tpls/mpark-variant + ${NLOHMANN_INCLUDE_DIR} + ${SPDLOG_INCLUDE_DIR}) + +target_link_libraries(xacc PUBLIC CppMicroServices) + if(LIBUNWIND_FOUND) -message( - STATUS "${BoldGreen}Building xacc with libunwind support.${ColorReset}") + message(STATUS "${BoldGreen}Building xacc with libunwind support.${ColorReset}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAS_LIBUNWIND") - target_include_directories(xacc - PRIVATE ${CMAKE_BINARY_DIR} - ${CPR_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include - ${CMAKE_SOURCE_DIR}/tpls/cxxopts - ${LIBUNWIND_INCLUDE_DIRS} - PUBLIC . - ir - compiler - program - accelerator - accelerator/remote - utils - service - algorithm - optimizer - ${CMAKE_SOURCE_DIR}/tpls/mpark-variant - ${NLOHMANN_INCLUDE_DIR} - ${SPDLOG_INCLUDE_DIR}) - - target_link_libraries(xacc - PUBLIC CppMicroServices - PRIVATE cpr - ${LIBUNWIND_LIBRARIES} - ${LIBUNWINDX86_LIBRARIES}) - # linking against MPI libraries found by cmake - if(MPI_FOUND) - target_link_libraries(xacc PUBLIC CppMicroServices ${MPI_CXX_LIBRARIES}) - endif() - -else() + target_include_directories(xacc PRIVATE ${LIBUNWIND_INCLUDE_DIRS}) + target_link_libraries(xacc PUBLIC ${LIBUNWIND_LIBRARIES} + ${LIBUNWINDX86_LIBRARIES}) +endif() - target_include_directories(xacc - PRIVATE ${CMAKE_BINARY_DIR} - ${CPR_INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include - ${CMAKE_SOURCE_DIR}/tpls/cxxopts - PUBLIC . - ir - compiler - program - accelerator - accelerator/remote - utils - service - algorithm - optimizer - ${CMAKE_SOURCE_DIR}/tpls/mpark-variant - ${NLOHMANN_INCLUDE_DIR} - ${SPDLOG_INCLUDE_DIR}) - - target_link_libraries(xacc PUBLIC CppMicroServices PRIVATE cpr) - # linking against MPI libraries found by cmake - if(MPI_FOUND) - target_link_libraries(xacc PUBLIC ${MPI_CXX_LIBRARIES}) - endif() +if(MPI_FOUND) + include_directories(${MPI_CXX_HEADER_DIR}) + target_link_libraries(xacc PUBLIC ${MPI_CXX_LIBRARIES}) +endif() +if(XACC_REMOTE_ACCELERATORS) + target_include_directories(xacc PUBLIC accelerator/remote PRIVATE ${CPR_INCLUDE_DIRS}) + target_link_libraries(xacc PRIVATE cpr) endif() target_compile_features(xacc diff --git a/xacc/xacc.cpp b/xacc/xacc.cpp index c67fa1b7c..1ca2243e7 100644 --- a/xacc/xacc.cpp +++ b/xacc/xacc.cpp @@ -347,6 +347,8 @@ std::shared_ptr getAccelerator() { } return acc; } + +#ifndef REMOTE_DISABLED std::shared_ptr getAccelerator(const std::string &name, std::shared_ptr client, const HeterogeneousMap ¶ms) { @@ -380,6 +382,7 @@ std::shared_ptr getAccelerator(const std::string &name, } return acc; } +#endif std::shared_ptr getAccelerator(const std::string &name, const HeterogeneousMap ¶ms) { diff --git a/xacc/xacc.hpp b/xacc/xacc.hpp index 5bc911c2c..83087934f 100644 --- a/xacc/xacc.hpp +++ b/xacc/xacc.hpp @@ -15,7 +15,9 @@ #include "AlgorithmGradientStrategy.hpp" #include "Compiler.hpp" -#include "RemoteAccelerator.hpp" +#ifndef REMOTE_DISABLED + #include "RemoteAccelerator.hpp" +#endif #include "IRProvider.hpp" #include "Algorithm.hpp" @@ -138,9 +140,11 @@ getClassicalRegHostBuffer(const std::string &cRegName); void setAccelerator(const std::string &acceleratorName); std::shared_ptr getAccelerator(const std::string &name, const HeterogeneousMap ¶ms = {}); +#ifndef REMOTE_DISABLED std::shared_ptr getAccelerator(const std::string &name, std::shared_ptr client, const HeterogeneousMap ¶ms = {}); +#endif std::shared_ptr getAccelerator(); std::shared_ptr getAcceleratorDecorator(const std::string &decorator, From 7d914d5fbf452a0d53793909f4ee94d2b9b1108d Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 29 Jul 2024 15:13:15 -0400 Subject: [PATCH 048/101] Fix IWYU error --- xacc/utils/Utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xacc/utils/Utils.cpp b/xacc/utils/Utils.cpp index 39ebab577..829504a37 100644 --- a/xacc/utils/Utils.cpp +++ b/xacc/utils/Utils.cpp @@ -12,6 +12,7 @@ *******************************************************************************/ #include "Utils.hpp" #include +#include #include "RuntimeOptions.hpp" #include From e4250dd7d8a79585ea05970af0c24b502c73729b Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 29 Jul 2024 15:23:00 -0400 Subject: [PATCH 049/101] Fix target linking --- xacc/CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index 22e0242de..625cb52e7 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -62,8 +62,6 @@ if(LIBUNWIND_FOUND) target_link_libraries(xacc PRIVATE ${LIBUNWIND_LIBRARIES} ${LIBUNWINDX86_LIBRARIES} - PUBLIC - spdlog::spdlog ) endif() @@ -87,9 +85,13 @@ target_include_directories(xacc ${CMAKE_SOURCE_DIR}/tpls/mpark-variant ${NLOHMANN_INCLUDE_DIR} ) -target_link_libraries(xacc PUBLIC CppMicroServices) -target_link_libraries(xacc PRIVATE cpr::cpr) - +target_link_libraries(xacc + PUBLIC + CppMicroServices + spdlog::spdlog + PRIVATE + cpr::cpr +) # linking against MPI libraries found by cmake if(MPI_FOUND) From cb8d86da976eb9539c4cb98b67d0ce0539d7243b Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 29 Jul 2024 21:00:29 +0000 Subject: [PATCH 050/101] Removed armadillo from qubit tapering Signed-off-by: Daniel Claudino --- .../qubit-tapering/CMakeLists.txt | 2 +- .../qubit-tapering/qubit_tapering.cpp | 68 +++++++++---------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/quantum/plugins/observable_transforms/qubit-tapering/CMakeLists.txt b/quantum/plugins/observable_transforms/qubit-tapering/CMakeLists.txt index 4667d36bd..f720f4e41 100644 --- a/quantum/plugins/observable_transforms/qubit-tapering/CMakeLists.txt +++ b/quantum/plugins/observable_transforms/qubit-tapering/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) # L-BFGS++ will require Eigen, XACC provides it target_include_directories(${LIBRARY_NAME} PUBLIC . - ${XACC_ROOT}/include/eigen ${XACC_ROOT}/include/armadillo) + ${XACC_ROOT}/include/eigen) # _bundle_name must be == manifest.json bundle.symbolic_name !!! set(_bundle_name xacc_qubit_tapering) diff --git a/quantum/plugins/observable_transforms/qubit-tapering/qubit_tapering.cpp b/quantum/plugins/observable_transforms/qubit-tapering/qubit_tapering.cpp index fb2185d96..0ceb70fed 100644 --- a/quantum/plugins/observable_transforms/qubit-tapering/qubit_tapering.cpp +++ b/quantum/plugins/observable_transforms/qubit-tapering/qubit_tapering.cpp @@ -1,6 +1,9 @@ #include "qubit_tapering.hpp" -#include +#include +#include +#include + #include #include "FermionOperator.hpp" @@ -17,8 +20,7 @@ bool ptr_is_a(std::shared_ptr ptr) { } std::shared_ptr QubitTapering::transform( std::shared_ptr Hptr_input) { - - // First we pre-process the observable to a PauliOperator + // First we pre-process the observable to a PauliOperator auto obs_str = Hptr_input->toString(); auto fermi_to_pauli = xacc::getService("jw"); std::shared_ptr Hptr; @@ -274,27 +276,28 @@ const double QubitTapering::computeGroundStateEnergy(PauliOperator &op, const int n) { auto n_qubits = op.nQubits(); auto n_hilbert = std::pow(2, n_qubits); - using SparseMatrix = arma::SpMat>; + using SparseMatrix = Eigen::SparseMatrix>; SparseMatrix x(2, 2), y(2, 2), z(2, 2); - x(0, 1) = 1.0; - x(1, 0) = 1.0; - y(0, 1) = std::complex(0, -1); - y(1, 0) = std::complex(0, 1); - z(0, 0) = 1.; - z(1, 1) = -1.; + x.coeffRef(0, 1) = 1.0; + x.coeffRef(1, 0) = 1.0; + y.coeffRef(0, 1) = std::complex(0, -1); + y.coeffRef(1, 0) = std::complex(0, 1); + z.coeffRef(0, 0) = 1.0; + z.coeffRef(1, 1) = -1.0; - SparseMatrix i = arma::speye(2, 2); + SparseMatrix i = SparseMatrix(2, 2); + i.setIdentity(); std::map mat_map{ {"I", i}, {"X", x}, {"Y", y}, {"Z", z}}; - auto kron_ops = [](std::vector &ops) { - auto first = ops[0]; - for (int i = 1; i < ops.size(); i++) { - first = arma::kron(first, ops[i]); + auto kron_ops = [](const std::vector &ops) { + SparseMatrix result = ops[0]; + for (size_t i = 1; i < ops.size(); ++i) { + result = Eigen::kroneckerProduct(result, ops[i]).eval(); } - return first; + return result; }; SparseMatrix total(n_hilbert, n_hilbert); @@ -306,14 +309,15 @@ const double QubitTapering::computeGroundStateEnergy(PauliOperator &op, if (term.second.ops().empty()) { // this was I term - auto id = arma::speye(n_hilbert, n_hilbert); + SparseMatrix id(n_hilbert, n_hilbert); + id.setIdentity(); sparse_mats.push_back(id); } else { for (auto &pauli : term.second.ops()) { if (pauli.first > tensor_factor) { - auto id_qbits = pauli.first - tensor_factor; - auto id = arma::speye((int)std::pow(2, id_qbits), - (int)std::pow(2, id_qbits)); + int id_qbits = pauli.first - tensor_factor; + SparseMatrix id((int)std::pow(2, id_qbits), (int)std::pow(2, id_qbits)); + id.setIdentity(); sparse_mats.push_back(id); } @@ -322,7 +326,8 @@ const double QubitTapering::computeGroundStateEnergy(PauliOperator &op, } for (int i = tensor_factor; i < n_qubits; i++) { - auto id = arma::speye(2, 2); + SparseMatrix id(2, 2); + id.setIdentity(); sparse_mats.push_back(id); } } @@ -331,18 +336,13 @@ const double QubitTapering::computeGroundStateEnergy(PauliOperator &op, sp_matrix *= coeff; total += sp_matrix; } + Eigen::VectorXd eigval; + Eigen::MatrixXd eigvec; - arma::vec eigval; - arma::mat eigvec; - - arma::sp_mat test(total.n_rows, total.n_cols); - for (auto i = total.begin(); i != total.end(); ++i) { - test(i.row(), i.col()) = (*i).real(); - } - - arma::eigs_sym(eigval, eigvec, test, 1); + Eigen::SparseMatrix real_total = total.real(); + Eigen::SelfAdjointEigenSolver solver(real_total); - double reducedEnergy = eigval(0); + double reducedEnergy = solver.eigenvalues()[0]; return reducedEnergy; } @@ -422,9 +422,7 @@ Eigen::MatrixXi QubitTapering::gauss(Eigen::MatrixXi &A, if (k > ip) { for (int j = i; j < m; j++) { - auto tmp = A(k, j); - A(k, j) = A(ip, j); - A(ip, j) = tmp; + std::swap(A(k, j), A(ip, j)); } } @@ -454,4 +452,4 @@ Eigen::MatrixXi QubitTapering::gauss(Eigen::MatrixXi &A, } // namespace xacc -REGISTER_PLUGIN(xacc::QubitTapering, xacc::ObservableTransform) \ No newline at end of file +REGISTER_PLUGIN(xacc::QubitTapering, xacc::ObservableTransform) From ab0bc3c533578013d26ae0a7a8662534a4c9c54d Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 30 Jul 2024 10:58:56 -0400 Subject: [PATCH 051/101] Changed optimizer in QAOATester to pass Mac CI tests Signed-off-by: Daniel Claudino --- quantum/plugins/algorithms/qaoa/tests/QAOATester.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/algorithms/qaoa/tests/QAOATester.cpp b/quantum/plugins/algorithms/qaoa/tests/QAOATester.cpp index 287a5dfb3..d916e90f6 100644 --- a/quantum/plugins/algorithms/qaoa/tests/QAOATester.cpp +++ b/quantum/plugins/algorithms/qaoa/tests/QAOATester.cpp @@ -51,7 +51,7 @@ TEST(QAOATester, checkStandardParamterizedScheme) { auto acc = xacc::getAccelerator("qpp"); auto buffer = xacc::qalloc(2); - auto optimizer = xacc::getOptimizer("nlopt"); + auto optimizer = xacc::getOptimizer("nlopt", std::make_pair("nlopt-optimizer", "nelder-mead")); auto qaoa = xacc::getService("QAOA"); // Create deuteron Hamiltonian auto H_N_2 = xacc::quantum::getObservable( From 48f9d023d25f1d4d6ccf2035213da6ae3ba4081b Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 30 Jul 2024 17:57:11 +0000 Subject: [PATCH 052/101] Fixed tpls/CmakeLists.txt to bypass cpr if remote accelerators are disabled Signed-off-by: Daniel Claudino --- tpls/CMakeLists.txt | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tpls/CMakeLists.txt b/tpls/CMakeLists.txt index 02db034d1..e9091ebd5 100644 --- a/tpls/CMakeLists.txt +++ b/tpls/CMakeLists.txt @@ -32,21 +32,23 @@ add_subdirectory(cppmicroservices) # Fix for bug #161 install(FILES "${CMAKE_BINARY_DIR}/tpls/cppmicroservices/CMakeFiles/Export/share/cppmicroservices4/cmake/CppMicroServicesTargets-release.cmake" DESTINATION share/cppmicroservices4/cmake OPTIONAL) -if (XACC_DEPS_EXTERNAL) - find_package(cpr) - if (cpr_FOUND) - set(XACC_USE_EXTERNAL_CPR TRUE) - set (XACC_USE_EXTERNAL_CPR ${XACC_USE_EXTERNAL_CPR} PARENT_SCOPE) - message(STATUS "${BoldGreen}cpr: Found system installation config at ${cpr_DIR}${ColorReset}") - endif() -endif() +if(XACC_REMOTE_ACCELERATORS) + if (XACC_DEPS_EXTERNAL) + find_package(cpr) + if (cpr_FOUND) + set(XACC_USE_EXTERNAL_CPR TRUE) + set (XACC_USE_EXTERNAL_CPR ${XACC_USE_EXTERNAL_CPR} PARENT_SCOPE) + message(STATUS "${BoldGreen}cpr: Found system installation config at ${cpr_DIR}${ColorReset}") + endif() + endif() -if (NOT XACC_USE_EXTERNAL_CPR) - set(CPR_FORCE_USE_SYSTEM_CURL ON CACHE BOOL "" FORCE) - set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE) - set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) - set(BUILD_SHARED_LIBS FALSE) - add_subdirectory(cpr) + if (NOT XACC_USE_EXTERNAL_CPR) + set(CPR_FORCE_USE_SYSTEM_CURL ON CACHE BOOL "" FORCE) + set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) + set(BUILD_SHARED_LIBS FALSE) + add_subdirectory(cpr) + endif() endif() if(XACC_BUILD_TESTS) From b1ae8af39b9af4bc4c9c79e43462f41b1c5387f1 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 31 Jul 2024 08:33:16 -0400 Subject: [PATCH 053/101] Update nlohmann_json to 3.11 --- .../plugins/ibm/accelerator/IBMAccelerator.cpp | 16 +++++++--------- .../ibm/accelerator/QObjectExperimentVisitor.hpp | 8 +++----- quantum/plugins/ibm/compiler/QObjectCompiler.cpp | 10 ++++------ tpls/nlohmann | 2 +- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp b/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp index ac8c50791..c3e5e1f89 100644 --- a/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp +++ b/quantum/plugins/ibm/accelerator/IBMAccelerator.cpp @@ -187,7 +187,7 @@ bool hasMidCircuitMeasurement( } bool IBMAccelerator::verifyJobsLimit(std::string& curr_backend) { - + // Get backend jobs limit std::string getJobsLimitPath = "/api/Network/" + hub + "/Groups/" + group + "/Projects/" + project + "/devices/" + curr_backend + @@ -204,13 +204,13 @@ bool IBMAccelerator::verifyJobsLimit(std::string& curr_backend) { } void IBMAccelerator::processBackendCandidate(nlohmann::json& backend_json) { - // First of all filter by count fo qubits + // First of all filter by count fo qubits if (requested_n_qubits > 0) { if( backend_json.count("n_qubits") ) { int nqubits = backend_json["n_qubits"].get(); if(nqubits < requested_n_qubits) { return; - } + } } else { return; } @@ -449,8 +449,7 @@ std::string QasmQObjGenerator::getQObjJsonStr( qobj.set_header(qobjHeader); // Create the JSON String to send - nlohmann::json j; - nlohmann::to_json(j, qobj); + nlohmann::json j = qobj; return j.dump(); } @@ -561,8 +560,7 @@ std::string PulseQObjGenerator::getQObjJsonStr( root.set_backend(b); root.set_shots(shots); - nlohmann::json jj; - nlohmann::to_json(jj, root.get_q_object()); + nlohmann::json jj= root.get_q_object(); return jj.dump(); } @@ -1020,7 +1018,7 @@ void IBMAccelerator::contributeInstructions( pulseParams["duration"].get(); inst->setDuration(parametricPulseDuration); } - + // Delay pulse has a duration if (inst_name == "delay") { inst->setDuration((*seq_iter)["duration"].get()); @@ -1320,7 +1318,7 @@ IBMAccelerator::getNativeCode(std::shared_ptr program, // qc.qasm() breaks when circuit qc contains gates with classical conditioning on a single cbit // Please note that this is a limitation of **OpenQASM** only, // i.e., qiskit's QuantumCircuit and QObj can both handle classical conditioning on a single cbit. - // Our native code gen strategy here is to + // Our native code gen strategy here is to // convert multi-qreg indexing into multiple single-cbit registers: // i.e., c[3] -> c3 (single-bit register) // This only happens when classical conditioning on a single cbit is needed. diff --git a/quantum/plugins/ibm/accelerator/QObjectExperimentVisitor.hpp b/quantum/plugins/ibm/accelerator/QObjectExperimentVisitor.hpp index 024297e76..76f82d1ba 100644 --- a/quantum/plugins/ibm/accelerator/QObjectExperimentVisitor.hpp +++ b/quantum/plugins/ibm/accelerator/QObjectExperimentVisitor.hpp @@ -65,9 +65,7 @@ class QObjectExperimentVisitor : public AllGateVisitor { } const std::string toString() override { - experiment = getExperiment(); - nlohmann::json json; - nlohmann::to_json(json, experiment); + nlohmann::json json = getExperiment(); return json.dump(); } @@ -106,7 +104,7 @@ class QObjectExperimentVisitor : public AllGateVisitor { experiment.set_config(config); experiment.set_header(header); // xacc::info("Adding insts " + std::to_string(instructions.to)) - + // Note: the experiment was constructed in terms of { u1, u2, u3, cx} gate set. // U + CX gate set if (gateSet == GateSet::U_CX) { @@ -126,7 +124,7 @@ class QObjectExperimentVisitor : public AllGateVisitor { // Copy the instruction and only update the name + params. // This is to make sure information about Bfunc (conditional) etc. // is copied to the decomposed gate sequence. - + // Note: this decomposition is adapted from Qiskit Terra, // see qiskit/circuit/library/standard_gates/equivalence_library.py const auto u2_params = inst.get_params(); diff --git a/quantum/plugins/ibm/compiler/QObjectCompiler.cpp b/quantum/plugins/ibm/compiler/QObjectCompiler.cpp index dc1bed69a..b530fb74b 100644 --- a/quantum/plugins/ibm/compiler/QObjectCompiler.cpp +++ b/quantum/plugins/ibm/compiler/QObjectCompiler.cpp @@ -40,7 +40,7 @@ std::shared_ptr QObjectCompiler::compile(const std::string &src, auto ir = provider->createIR(); auto json = nlohmann::json::parse(jsonstr); xacc::ibm::QObjectRoot qobj; - nlohmann::from_json(json, qobj); + json.get_to(qobj); auto experiments = qobj.get_q_object().get_experiments(); for (auto &e : experiments) { @@ -108,7 +108,7 @@ QObjectCompiler::translate(std::shared_ptr function) auto uniqueBits = function->uniqueBits(); // The number of qubits required for an experiment is the number of *physical* qubits, - // i.e. the max index of qubit used in the circuit. + // i.e. the max index of qubit used in the circuit. auto nbRequiredBits = function->nPhysicalBits(); auto visitor = std::make_shared(function->name(), nbRequiredBits); @@ -152,8 +152,7 @@ QObjectCompiler::translate(std::shared_ptr function) root.set_q_object(qobj); // Create the JSON String to send - nlohmann::json j; - nlohmann::to_json(j, root); + nlohmann::json j = root; return j.dump(); } @@ -220,8 +219,7 @@ QObjectCompiler::translate(std::shared_ptr function, root.set_q_object(qobj); // Create the JSON String to send - nlohmann::json j; - nlohmann::to_json(j, root); + nlohmann::json j = root; return j.dump(); } } // namespace quantum diff --git a/tpls/nlohmann b/tpls/nlohmann index 8968adcd5..9cca280a4 160000 --- a/tpls/nlohmann +++ b/tpls/nlohmann @@ -1 +1 @@ -Subproject commit 8968adcd53951b652f9f480ad62e66dc2714b061 +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03 From 7b712ff4355d202ab3cdc08eda7bcdd51a29e6f3 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 2 Aug 2024 11:00:38 -0400 Subject: [PATCH 054/101] Revert accidental changes due to merge conflicts --- quantum/plugins/ibm/CMakeLists.txt | 12 ++++++++---- tpls/nlopt | 2 +- xacc/CMakeLists.txt | 9 +++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index ee6c5cdc9..103829747 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -42,10 +42,14 @@ target_include_directories(${LIBRARY_NAME} ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include) target_link_libraries(${LIBRARY_NAME} - PUBLIC xacc - xacc-quantum-gate - ${ANTLR_LIB} - CppMicroServices PRIVATE cpr::cpr) + PUBLIC + xacc + xacc-quantum-gate + ${ANTLR_LIB} + CppMicroServices + PRIVATE + cpr::cpr +) if(XACC_REMOTE_ACCELERATORS) target_link_libraries(${LIBRARY_NAME} PRIVATE cpr) diff --git a/tpls/nlopt b/tpls/nlopt index dc4ad82b6..95172af2b 160000 --- a/tpls/nlopt +++ b/tpls/nlopt @@ -1 +1 @@ -Subproject commit dc4ad82b6e374619efa423b585f7f96b875b2cb7 +Subproject commit 95172af2b2ef8742c2da6deeedab5f4d9d919706 diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index b72b15859..f6c827d79 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -55,7 +55,6 @@ add_library(xacc SHARED ${SOURCES}) target_include_directories(xacc PRIVATE ${CMAKE_BINARY_DIR} - ${CPR_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/tpls/rapidjson/include ${CMAKE_SOURCE_DIR}/tpls/cxxopts PUBLIC @@ -64,7 +63,6 @@ target_include_directories(xacc compiler program accelerator - accelerator/remote utils service algorithm @@ -79,17 +77,16 @@ target_link_libraries(xacc ) if(LIBUNWIND_FOUND) - message( - STATUS "${BoldGreen}Building xacc with libunwind support.${ColorReset}") + message(STATUS "${BoldGreen}Building xacc with libunwind support.${ColorReset}") target_compile_definitions(xacc PUBLIC "-DHAS_LIBUNWIND") - target_include_directories(xacc + target_include_directories(xacc PRIVATE ${LIBUNWIND_INCLUDE_DIRS}) + target_link_libraries(xacc PUBLIC ${LIBUNWIND_LIBRARIES} ${LIBUNWINDX86_LIBRARIES} ) endif() -# linking against MPI libraries found by cmake if(MPI_FOUND) include_directories(${MPI_CXX_HEADER_DIR}) target_link_libraries(xacc PUBLIC ${MPI_CXX_LIBRARIES}) From 7d36c81eb17fedb5e8872d951a1877248f68996e Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 2 Aug 2024 19:31:46 +0000 Subject: [PATCH 055/101] WIP IBM update Signed-off-by: Daniel Claudino --- .gitmodules | 3 + quantum/plugins/ibm/CMakeLists.txt | 1 + quantum/plugins/ibm/new_aer/CMakeLists.txt | 88 ++ .../plugins/ibm/new_aer/aer_accelerator.cpp | 1077 +++++++++++++++++ .../plugins/ibm/new_aer/aer_accelerator.hpp | 94 ++ .../plugins/ibm/new_aer/aer_noise_model.hpp | 63 + quantum/plugins/ibm/new_aer/manifest.json | 6 + .../plugins/ibm/new_aer/tests/CMakeLists.txt | 22 + .../new_aer/tests/NewAerAcceleratorTester.cpp | 226 ++++ tpls/qiskit-aer | 1 + 10 files changed, 1581 insertions(+) create mode 100644 quantum/plugins/ibm/new_aer/CMakeLists.txt create mode 100644 quantum/plugins/ibm/new_aer/aer_accelerator.cpp create mode 100644 quantum/plugins/ibm/new_aer/aer_accelerator.hpp create mode 100644 quantum/plugins/ibm/new_aer/aer_noise_model.hpp create mode 100644 quantum/plugins/ibm/new_aer/manifest.json create mode 100644 quantum/plugins/ibm/new_aer/tests/CMakeLists.txt create mode 100644 quantum/plugins/ibm/new_aer/tests/NewAerAcceleratorTester.cpp create mode 160000 tpls/qiskit-aer diff --git a/.gitmodules b/.gitmodules index ef75a52d5..e9d029278 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "tpls/eigen"] path = tpls/eigen url = https://gitlab.com/libeigen/eigen.git +[submodule "tpls/qiskit-aer"] + path = tpls/qiskit-aer + url = https://github.com/Qiskit/qiskit-aer.git \ No newline at end of file diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index b13660b0b..fd78f91f0 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -12,6 +12,7 @@ # *******************************************************************************/ add_subdirectory(aer) +add_subdirectory(new_aer) set(LIBRARY_NAME xacc-ibm) diff --git a/quantum/plugins/ibm/new_aer/CMakeLists.txt b/quantum/plugins/ibm/new_aer/CMakeLists.txt new file mode 100644 index 000000000..2da52c11c --- /dev/null +++ b/quantum/plugins/ibm/new_aer/CMakeLists.txt @@ -0,0 +1,88 @@ +set(LIBRARY_NAME xacc-new-aer) + +if(NOT QIREE_MINIMAL_BUILD) +#add_subdirectory(py-aer) +endif() + +set(AER_SOURCE_DIR ${CMAKE_SOURCE_DIR}/tpls/qiskit-aer) + +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") + if (NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + set(AER_SIMD_SOURCE_FILE ${AER_SOURCE_DIR}/src/simulators/statevector/qv_avx2.cpp) + endif() +endif() + +file(GLOB SRC + aer_accelerator.cpp + ${AER_SIMD_SOURCE_FILE}) + +usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC) +usfunctiongeneratebundleinit(TARGET ${LIBRARY_NAME} OUT SRC) + +add_library(${LIBRARY_NAME} SHARED ${SRC}) + +find_package(Python COMPONENTS Interpreter Development) + +target_include_directories(${LIBRARY_NAME} + PUBLIC . + ${AER_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/tpls + ${CMAKE_SOURCE_DIR}/tpls/pybind11/include + ${Python_INCLUDE_DIRS}) + +target_link_libraries(${LIBRARY_NAME} + PUBLIC xacc + xacc-quantum-gate + Python::Python + ) + +if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + if(APPLE OR UNIX) + if (NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + set_source_files_properties(${AER_SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "-march=native -mfma -mavx2") + endif() + endif() +endif() + +find_package(OpenMP) +if(OpenMP_CXX_FOUND) + target_link_libraries(${LIBRARY_NAME} PUBLIC OpenMP::OpenMP_CXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + +set(_bundle_name xacc_new_aer) +set_target_properties(${LIBRARY_NAME} + PROPERTIES COMPILE_DEFINITIONS + US_BUNDLE_NAME=${_bundle_name} + US_BUNDLE_NAME + ${_bundle_name}) + +usfunctionembedresources(TARGET + ${LIBRARY_NAME} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + FILES + manifest.json) + +if(APPLE) + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "@loader_path/../lib") + set_target_properties(${LIBRARY_NAME} + PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +else() + if(LAPACK_FOUND) + target_link_libraries(${LIBRARY_NAME} PRIVATE ${LAPACK_LIBRARIES}) + else() + message(STATUS "LAPACK NOT FOUND. Aer plugin may not work.") + endif() + set_target_properties(${LIBRARY_NAME} + PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") + set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared") +endif() + +if(XACC_BUILD_TESTS) + add_subdirectory(tests) +endif() + +install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) + diff --git a/quantum/plugins/ibm/new_aer/aer_accelerator.cpp b/quantum/plugins/ibm/new_aer/aer_accelerator.cpp new file mode 100644 index 000000000..c56e51176 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/aer_accelerator.cpp @@ -0,0 +1,1077 @@ +/******************************************************************************* + * Copyright (c) 2019 UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompanies this + * distribution. The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution + *License is available at https://eclipse.org/org/documents/edl-v10.php + * + * Contributors: + * Thien Nguyen - initial API and implementation + *******************************************************************************/ +#include "aer_accelerator.hpp" +#include "Accelerator.hpp" +#include "Utils.hpp" +#include "aer_noise_model.hpp" +#include "CommonGates.hpp" +#include "CountGatesOfTypeVisitor.hpp" +#include "InstructionIterator.hpp" + +#include "controllers/aer_controller.hpp" +#include "controllers/controller_execute.hpp" +#include "noise/readout_error.hpp" + +#include "cppmicroservices/BundleActivator.h" +#include "cppmicroservices/BundleContext.h" +#include "cppmicroservices/ServiceProperties.h" +#include "simulators/density_matrix/densitymatrix.hpp" +#include "xacc.hpp" +#include "xacc_service.hpp" + +#include +#include +//#include "QObjGenerator.hpp" +//#include "py-aer/aer_python_adapter.hpp" + +namespace xacc { +namespace quantum { + +#define IS_INTEGRAL(T) \ + typename std::enable_if::value>::type * = 0 + +template +std::string integral_to_binary_string(T byte, IS_INTEGRAL(T)) { + std::bitset bs(byte); + return bs.to_string(); +} +std::string hex_string_to_binary_string(const std::string &hex) { + auto hex_char_to_bin = [](char c) -> std::string { + switch (toupper(c)) { + case '0': + return "0000"; + case '1': + return "0001"; + case '2': + return "0010"; + case '3': + return "0011"; + case '4': + return "0100"; + case '5': + return "0101"; + case '6': + return "0110"; + case '7': + return "0111"; + case '8': + return "1000"; + case '9': + return "1001"; + case 'A': + return "1010"; + case 'B': + return "1011"; + case 'C': + return "1100"; + case 'D': + return "1101"; + case 'E': + return "1110"; + case 'F': + return "1111"; + } + throw std::runtime_error("Invalid Hex character!"); + return ""; + }; + + // start with '0x' + assert(hex.substr(0, 2) == "0x"); + std::string bin; + for (int i = 2; i != hex.length(); ++i) { + bin += hex_char_to_bin(hex[i]); + } + + return bin; +} + +HeterogeneousMap AerAccelerator::getProperties() { + auto props = physical_backend_properties; + // Insert 'shots' data + if (m_simtype == "qasm") { + props.insert("shots", m_shots); + } + return props; +} + +void AerAccelerator::initialize(const HeterogeneousMap ¶ms) { + + m_options = params; + noise_model.clear(); + m_simtype = "qasm"; + connectivity.clear(); + if (params.stringExists("qobj-compiler") && + (xacc::hasService(params.getString("qobj-compiler")) || + xacc::hasContributedService( + params.getString("qobj-compiler")))) { + xacc_to_qobj = xacc::getCompiler(params.getString("qobj-compiler")); + } else { + xacc_to_qobj = xacc::getCompiler("qobj"); + } + if (params.keyExists("shots")) { + m_shots = params.get("shots"); + } + + if (params.keyExists("seed")) { + m_seed = params.get("seed"); + } + if (params.stringExists("sim-type")) { + if (!xacc::container::contains( + std::vector{"qasm", "statevector", "pulse", + "density_matrix", "matrix_product_state"}, + params.getString("sim-type"))) { + xacc::warning("[Aer] warning, invalid sim-type (" + + params.getString("sim-type") + + "), must be qasm or statevector or density_matrix or " + "matrix_product_state."); + } else { + m_simtype = params.getString("sim-type"); + } + } + + // A custom sim method is specified with 'shots'; + // use qasm sim but set the method in QObj to force the method. + // e.g., statevector and density_matrix will not do shots, just returns the + // 'state'. + if (m_simtype != "qasm" && params.keyExists("shots")) { + m_simtype = "qasm"; + } + + if (params.stringExists("backend")) { + auto ibm_noise_model = xacc::getService("IBM"); + ibm_noise_model->initialize(params); + auto json_str = ibm_noise_model->toJson(); + noise_model = nlohmann::json::parse(json_str); + auto ibm = xacc::getAccelerator("ibm:" + params.getString("backend")); + physical_backend_properties = ibm->getProperties(); + if (m_simtype == "pulse") { + // If pulse mode, must contribute pulse cmd-def. + ibm->contributeInstructions(); + } + // Set connectivity based on the backend: + connectivity = ibm->getConnectivity(); + } else if (params.stringExists("noise-model")) { + std::string noise_model_str = params.getString("noise-model"); + // Check if this is a file name + std::ifstream test(noise_model_str); + if (test) { + std::string str((std::istreambuf_iterator(test)), + std::istreambuf_iterator()); + noise_model = nlohmann::json::parse(str); + } else { + noise_model = nlohmann::json::parse(params.getString("noise-model")); + } + + // need this for ro error decorator + std::vector p01s, p10s; + auto errors = noise_model["errors"]; + for (auto error : errors) { + if (error["operations"].get>() == + std::vector{"measure"}) { + auto probs = + error["probabilities"].get>>(); + auto meas1prep0 = probs[0][1]; + auto meas0prep1 = probs[1][0]; + p01s.push_back(meas0prep1); + p10s.push_back(meas1prep0); + } + } + physical_backend_properties.insert("p01s", p01s); + physical_backend_properties.insert("p10s", p10s); + + } + AER::Hacks::maybe_load_openmp(""); + initialized = true; +} + +double AerAccelerator::calcExpectationValueZ( + const std::vector> &in_stateVec, + const std::vector &in_bits) { + const auto hasEvenParity = + [](size_t x, const std::vector &in_qubitIndices) -> bool { + size_t count = 0; + for (const auto &bitIdx : in_qubitIndices) { + if (x & (1ULL << bitIdx)) { + count++; + } + } + return (count % 2) == 0; + }; + + double result = 0.0; + for (uint64_t i = 0; i < in_stateVec.size(); ++i) { + result += (hasEvenParity(i, in_bits) ? 1.0 : -1.0) * + std::norm(std::complex(in_stateVec[i].first, + in_stateVec[i].second)); + } + + return result; +} + +double AerAccelerator::calcExpectationValueZFromDensityMatrix( + const std::vector>> &in_densityMat, + const std::vector &in_bits) { + const auto hasEvenParity = + [](size_t x, const std::vector &in_qubitIndices) -> bool { + size_t count = 0; + for (const auto &bitIdx : in_qubitIndices) { + if (x & (1ULL << bitIdx)) { + count++; + } + } + return (count % 2) == 0; + }; + + double result = 0.0; + for (uint64_t i = 0; i < in_densityMat.size(); ++i) { + const auto &diag_elem = in_densityMat[i][i]; + // The diag. elements of the DM should be real. + assert(std::abs(diag_elem.second) < 1e-3); + // When using DM elements, don't need the square-norm. + result += ((hasEvenParity(i, in_bits) ? 1.0 : -1.0) * diag_elem.first); + } + + return result; +} + +void AerAccelerator::execute( + std::shared_ptr buffer, + const std::shared_ptr program) { + + if (m_simtype == "qasm") { + auto qobj_str = xacc_to_qobj->translate(program); + + nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"]; + j["config"]["shots"] = m_shots; + j["config"]["noise_model"] = noise_model; + // If a seed was set: + if (m_seed > 0) { + j["config"]["seed_simulator"] = m_seed; + } + + if (m_options.stringExists("sim-type")) { + const std::string requestedMethod = m_options.getString("sim-type"); + if (requestedMethod == "statevector") { + j["config"]["method"] = "statevector"; + } else if (requestedMethod == "density_matrix") { + j["config"]["method"] = "density_matrix"; + } else if (requestedMethod == "matrix_product_state") { + j["config"]["method"] = "matrix_product_state"; + } else { + j["config"]["method"] = "automatic"; + } + } + + // xacc::set_verbose(true); + // xacc::info("Shots Qobj:\n" + j.dump(2)); + // Initialize QOBJ + AER::Qobj qobj(j); + AER::Controller controller; + // Set config + controller.set_config(qobj.config); + assert(qobj.circuits.size() == 1); + + if (m_options.keyExists>>( + "initial_state")) { + const std::vector> intial_state = + m_options.get>>("initial_state"); + if (intial_state.size() != (1ULL << buffer->size())) { + xacc::error("Dimension mismatch in 'initial_state', expected size of " + + std::to_string(1ULL << buffer->size())); + } + const double norm = std::accumulate( + intial_state.begin(), intial_state.end(), 0.0, + [](double current_norm, const std::complex &val) { + return current_norm + std::norm(val); + }); + if (std::abs(norm - 1.0) > 1e-12) { + xacc::error("Initial state vector input is not normalized."); + } + // Add initialize op to set the initial input state + AER::Operations::Op op; + op.type = AER::Operations::OpType::initialize; + op.name = "initialize"; + for (int q = 0; q < buffer->size(); ++q) { + op.qubits.emplace_back(q); + } + op.params = intial_state; + qobj.circuits[0]->ops.insert(qobj.circuits[0]->ops.begin(), op); + qobj.circuits[0]->set_params(false); + } + + // Run qobj circuits + auto result = controller.execute(qobj.circuits, qobj.noise_model, qobj.config); + if (result.status != AER::Result::Status::completed) { + xacc::error("Failed to complete the simulation! Error: " + + result.message); + } + assert(result.results.size() == 1); + auto results = result.results.front(); + auto counts = + results.data.to_json()["counts"].get>(); + // Process bitStr to be an n-Measure string in msb + CountGatesOfTypeVisitor cc(program); + const int nMeasures = cc.countGates(); + for (auto &kv : counts) { + std::string hexStr = kv.first; + int nOccurrences = kv.second; + auto bitStr = hex_string_to_binary_string(hexStr); + std::string actual(nMeasures, '0'); + for (int i = 0; i < nMeasures; i++) { + if (bitStr.length() > i) { + actual[actual.length() - 1 - i] = bitStr[bitStr.length() - i - 1]; + } + } + buffer->appendMeasurement(actual, nOccurrences); + } + } /*else if (m_simtype == "pulse") { + // Get the correct QObject Generator + auto qobjGen = xacc::getService("pulse"); + auto chosenBackend = nlohmann::json::parse(physical_backend_properties.getString("config-json")); + // Unused + const std::string getBackendPropsResponse = "{}"; + auto defaults_response = nlohmann::json::parse(physical_backend_properties.getString("defaults-json")); + auto ibmPulseAssembler = xacc::getService("ibm-pulse"); + auto kernel = xacc::ir::asComposite(program->clone()); + + // Remove measures, add measure all (at the end) + kernel->clear(); + InstructionIterator iter(program); + std::vector measured_bits; + while (iter.hasNext()) { + auto next = iter.next(); + if (!next->isComposite() && next->name() != "Measure") { + kernel->addInstruction(next); + } else if (next->name() == "Measure") { + measured_bits.push_back(next->bits()[0]); + } + } + + auto provider = xacc::getIRProvider("quantum"); + for (size_t qId = 0; qId < buffer->size(); ++qId) { + kernel->addInstruction(provider->createInstruction("Measure", qId)); + } + + // Assemble pulse composite from the input kernel. + ibmPulseAssembler->apply(kernel, nullptr); + // Generate the QObject JSON + auto qobjJsonStr = qobjGen->getQObjJsonStr({kernel}, m_shots, chosenBackend, + getBackendPropsResponse, + connectivity, defaults_response); + xacc::info("Qobj:\n" + qobjJsonStr); + auto hamiltonianJson = chosenBackend["hamiltonian"]; + // Remove unrelated fields (could contain problematic characters) + hamiltonianJson.erase("description"); + hamiltonianJson.erase("h_latex"); + xacc::info("Hamiltonian Json:\n" + hamiltonianJson.dump()); + const auto dt = chosenBackend["dt"].get(); + const auto qubitFreqEst = defaults_response["qubit_freq_est"].get>(); + const auto uLoFreqs = chosenBackend["u_channel_lo"]; + std::vector uLoRefs; + for (auto loIter = uLoFreqs.begin(); loIter != uLoFreqs.end(); ++loIter) { + auto uLoConfig = *((*loIter).begin()); + uLoRefs.emplace_back(uLoConfig["q"].get()); + } + // Run the simulation via Python + const std::string resultJson = + xacc::aer::runPulseSim(hamiltonianJson.dump(), dt, qubitFreqEst, uLoRefs, qobjJsonStr); + auto result_json = nlohmann::json::parse(resultJson); + auto count_json = result_json["counts"].get>(); + for (const auto &[hexStr, nOccurrences] : count_json) { + auto bitStr = hex_string_to_binary_string(hexStr); + // Process bitStr to be an n-Measure string in msb + std::string actual = ""; + const auto nMeasures = measured_bits.size(); + for (int i = 0; i < nMeasures; i++) { + actual += "0"; + } + + for (int i = 0; i < nMeasures; i++) { + actual[actual.length() - 1 - i] = bitStr[bitStr.length() - measured_bits[i] - 1]; + } + + buffer->appendMeasurement(actual, nOccurrences); + } + + auto state_vector = result_json["statevector"].get>>(); + buffer->addExtraInfo("state", state_vector); + } else if (m_simtype == "density_matrix") { + // remove all measures, don't need them + auto tmp = xacc::ir::asComposite(program->clone()); + tmp->clear(); + AER::reg_t measured_bits; + InstructionIterator iter(program); + while (iter.hasNext()) { + auto next = iter.next(); + if (!next->isComposite() && next->name() != "Measure") { + tmp->addInstruction(next); + } else if (next->name() == "Measure") { + measured_bits.push_back(next->bits()[0]); + } + } + // In "density_matrix" simulation mode, always include Id gates + // if they are explicitly added to the Composite. + auto qobj_str = xacc_to_qobj->translate(tmp, {{"skip-id-gates", false}}); + nlohmann::json qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; + qObjJson["config"]["method"] = "density_matrix"; + qObjJson["config"]["enable_truncation"] = false; + qObjJson["config"]["noise_model"] = noise_model; + AER::DensityMatrix::State> densityMat; + AER::RngEngine rng; + AER::Qobj qobj(qObjJson); + // std::cout << "QObj:\n" << qobj_str << "\n"; + assert(qobj.circuits.size() == 1); + auto circ = qobj.circuits[0]; + // Output data container + AER::ExperimentResult data; + densityMat.initialize_creg(circ->num_memory, circ->num_registers); + densityMat.initialize_qreg(buffer->size()); + if (m_options.keyExists>>( + "initial_state")) { + const std::vector> intial_state = + m_options.get>>("initial_state"); + if (intial_state.size() != (1ULL << buffer->size())) { + xacc::error("Dimension mismatch in 'initial_state', expected size of " + + std::to_string(1ULL << buffer->size())); + } + const double norm = std::accumulate( + intial_state.begin(), intial_state.end(), 0.0, + [](double current_norm, const std::complex &val) { + return current_norm + std::norm(val); + }); + if (std::abs(norm - 1.0) > 1e-12) { + xacc::error("Initial state vector input is not normalized."); + } + densityMat.qreg().initialize_from_vector(intial_state); + } + // std::cout << "Num op: " << circ.ops.size() << "\n"; + if (!noise_model.empty()) { + auto noise = qobj.noise_model; + noise.enable_superop_method(); + auto opt_circ = noise.sample_noise( + circ, rng, AER::Noise::NoiseModel::Method::superop); + densityMat.apply_ops(opt_circ.ops.begin(), opt_circ.ops.end(), data, rng); + } else { + densityMat.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); + } + // std::cout << "Result: \n" << data.to_json().dump() << "\n"; + const double exp_val = densityMat.qreg().expval_pauli( + measured_bits, std::string(measured_bits.size(), 'Z')); + + auto dmData = densityMat.move_to_matrix(); + const auto length = dmData.size(); + assert(length == (1ULL << buffer->size()) * (1ULL << buffer->size())); + std::complex *dmPtr = dmData.move_to_buffer(); + std::vector> flattenDm; + flattenDm.reserve(length); + for (int i = 0; i < length; ++i) { + flattenDm.emplace_back(dmPtr[i].real(), dmPtr[i].imag()); + } + buffer->addExtraInfo("density_matrix", flattenDm); + + ExecutionInfo::DensityMatrixType dm(1ULL << buffer->size()); + auto *startAddr = dmPtr; + for (auto &row : dm) { + auto *endAddr = startAddr + (1ULL << buffer->size()); + row.assign(startAddr, endAddr); + startAddr = endAddr; + } + m_executionInfo = { + {ExecutionInfo::DmKey, + std::make_shared(std::move(dm))}}; + buffer->addExtraInfo("exp-val-z", exp_val); + }*/ + else { + assert(m_simtype == "statevector"); + // statevector + // remove all measures, don't need them + auto tmp = xacc::ir::asComposite(program->clone()); + tmp->clear(); + AER::reg_t measured_bits; + InstructionIterator iter(program); + while (iter.hasNext()) { + auto next = iter.next(); + if (!next->isComposite() && next->name() != "Measure") { + tmp->addInstruction(next); + } else if (next->name() == "Measure") { + measured_bits.push_back(next->bits()[0]); + } + } + auto qobj_str = xacc_to_qobj->translate(tmp); + nlohmann::json qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; + qObjJson["config"]["method"] = "statevector"; + qObjJson["config"]["enable_truncation"] = false; + AER::Statevector::State> stateVec; + AER::RngEngine rng; + AER::Qobj qobj(qObjJson); + // std::cout << "QObj:\n" << qobj_str << "\n"; + assert(qobj.circuits.size() == 1); + auto circ = qobj.circuits[0]; + // Output data container + AER::ExperimentResult data; + stateVec.initialize_creg(circ->num_memory, circ->num_registers); + stateVec.initialize_qreg(buffer->size()); + if (m_options.keyExists>>( + "initial_state")) { + const std::vector> intial_state = + m_options.get>>("initial_state"); + if (intial_state.size() != (1ULL << buffer->size())) { + xacc::error("Dimension mismatch in 'initial_state', expected size of " + + std::to_string(1ULL << buffer->size())); + } + const double norm = std::accumulate( + intial_state.begin(), intial_state.end(), 0.0, + [](double current_norm, const std::complex &val) { + return current_norm + std::norm(val); + }); + if (std::abs(norm - 1.0) > 1e-12) { + xacc::error("Initial state vector input is not normalized."); + } + stateVec.qreg().initialize_from_vector(intial_state); + } + // std::cout << "Num op: " << circ.ops.size() << "\n"; + stateVec.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); + // std::cout << "Result: \n" << data.to_json().dump() << "\n"; + const double exp_val = stateVec.qreg().expval_pauli( + measured_bits, std::string(measured_bits.size(), 'Z')); + + auto stateVecData = stateVec.move_to_vector(); + const auto length = stateVecData.size(); + std::complex *statePtr = stateVecData.move_to_buffer(); + ExecutionInfo::WaveFuncType wavefn(statePtr, statePtr + length); + // std::cout << "HOWDY: " << wavefn.size() << "\n"; + // for (int i = 0; i < wavefn.size(); ++i) { + // std::cout << wavefn[i] << "\n"; + // } + buffer->addExtraInfo("exp-val-z", exp_val); + m_executionInfo = { + {ExecutionInfo::WaveFuncKey, + std::make_shared(std::move(wavefn))}}; + } +} + +void AerAccelerator::execute( + std::shared_ptr buffer, + const std::vector> + compositeInstructions) { + for (auto &f : compositeInstructions) { + auto tmpBuffer = + std::make_shared(f->name(), buffer->size()); + execute(tmpBuffer, f); + buffer->appendChild(f->name(), tmpBuffer); + } +} + +void AerAccelerator::apply(std::shared_ptr buffer, + std::shared_ptr inst) { + static AER::Statevector::State> stateVec; + static auto provider = xacc::getIRProvider("quantum"); + static AER::RngEngine rng; + static std::set knownBuffers; + if (!xacc::container::contains(knownBuffers, buffer.get())) { + stateVec.initialize_qreg(buffer->size()); + knownBuffers.emplace(buffer.get()); + } + if (inst->isComposite() || inst->isAnalog()) { + xacc::error("Only gates are allowed."); + } + xacc::info("Apply: " + inst->toString()); + if (inst->name() != "Measure") { + auto tempComp = provider->createComposite("tmp"); + tempComp->addInstruction(inst); + auto qobj_str = xacc_to_qobj->translate(tempComp); + auto qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; + qObjJson["config"]["enable_truncation"] = false; + AER::Qobj qobj(qObjJson); + // std::cout << "QObj:\n" << qobj_str << "\n"; + assert(qobj.circuits.size() == 1); + auto circ = qobj.circuits[0]; + // Output data container + AER::ExperimentResult data; + // std::cout << "Num op: " << circ.ops.size() << "\n"; + stateVec.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); + // std::cout << "Result: \n" << data.to_json().dump() << "\n"; + // auto wavefn = stateVec.copy_to_vector(0); + // std::cout << "HOWDY: " << wavefn.size() << "\n"; + // for (int i = 0; i < wavefn.size(); ++i) { + // std::cout << wavefn[i] << "\n"; + // } + } + // stateVec.add_creg_to_data(data); + // If it was a Measure op: + else { + AER::reg_t measured_bits{inst->bits()[0]}; + const auto probs = stateVec.qreg().probabilities(measured_bits); + assert(probs.size() == 2); + assert(std::abs(1.0 - probs[0] - probs[1]) < 1e-12); + // Randomly pick outcome and return pair + auto outcome = rng.rand_int(probs); + // std::cout << "Outcome: " << outcome << "\n"; + assert(outcome == 0 || outcome == 1); + // std::cout << "Probs: " << probs[0] << " " << probs[1] << "\n"; + std::vector> mdiag(2, 0.); + mdiag[outcome] = 1. / std::sqrt(probs[outcome]); + stateVec.qreg().apply_diagonal_matrix(measured_bits, mdiag); + buffer->measure(inst->bits()[0], outcome); + } +} +/* +void IbmqNoiseModel::initialize(const HeterogeneousMap ¶ms) { + m_nbQubits = 0; + m_qubitT1.clear(); + m_qubitT2.clear(); + m_gateErrors.clear(); + m_gateDurations.clear(); + m_roErrors.clear(); + m_connectivity.clear(); + // Note: we support both remote backend JSON and cache JSON string. + // So that we can test this with offline JSON. + if (params.stringExists("backend") || params.stringExists("backend-json")) { + const auto backendJsonStr = [&]() { + if (params.stringExists("backend")) { + auto ibm = xacc::getAccelerator("ibm:" + params.getString("backend")); + auto props = ibm->getProperties().get("total-json"); + m_connectivity = ibm->getConnectivity(); + return props; + } + return params.getString("backend-json"); + }(); + + auto backEndJson = nlohmann::json::parse(backendJsonStr); + // Cache the backend properties JSON. + m_backendPropertiesJson = backendJsonStr; + // Parse qubit data: + auto qubitsData = backEndJson["qubits"]; + size_t nbQubit = 0; + for (auto qubitIter = qubitsData.begin(); qubitIter != qubitsData.end(); + ++qubitIter) { + std::optional meas0Prep1, meas1Prep0; + // Each qubit contains an array of properties. + for (auto probIter = qubitIter->begin(); probIter != qubitIter->end(); + ++probIter) { + const auto probObj = *probIter; + const std::string probName = probObj["name"].get(); + const double probVal = probObj["value"].get(); + const std::string unit = probObj["unit"].get(); + if (probName == "T1") { + assert(unit == "µs" || unit == "us" || unit == "ns"); + m_qubitT1.emplace_back( + (unit == "µs" || unit == "us") ? 1000.0 * probVal : probVal); + } + + if (probName == "T2") { + assert(unit == "µs" || unit == "us" || unit == "ns"); + m_qubitT2.emplace_back( + (unit == "µs" || unit == "us") ? 1000.0 * probVal : probVal); + } + + if (probName == "prob_meas0_prep1") { + assert(unit.empty()); + meas0Prep1 = probVal; + } + + if (probName == "prob_meas1_prep0") { + assert(unit.empty()); + meas1Prep0 = probVal; + } + } + assert(meas0Prep1.has_value() && meas1Prep0.has_value()); + m_roErrors.emplace_back(std::make_pair(*meas0Prep1, *meas1Prep0)); + + nbQubit++; + } + m_nbQubits = nbQubit; + assert(m_qubitT1.size() == m_nbQubits); + assert(m_qubitT2.size() == m_nbQubits); + assert(m_roErrors.size() == m_nbQubits); + + // Parse gate data: + auto gateData = backEndJson["gates"]; + for (auto gateIter = gateData.begin(); gateIter != gateData.end(); + ++gateIter) { + auto gateObj = *gateIter; + const std::string gateName = gateObj["name"].get(); + auto gateParams = gateObj["parameters"]; + for (auto it = gateParams.begin(); it != gateParams.end(); ++it) { + auto paramObj = *it; + const std::string paramName = paramObj["name"].get(); + if (paramName == "gate_length") { + const std::string unit = paramObj["unit"].get(); + assert(unit == "µs" || unit == "us" || unit == "ns"); + const double gateLength = + (unit == "µs" || unit == "us") + ? 1000.0 * paramObj["value"].get() + : paramObj["value"].get(); + const bool insertOk = + m_gateDurations.insert({gateName, gateLength}).second; + if (gateName.rfind("sx", 0) == 0) { + // This device properties were specified in the { rz, sx, cx } basis. + // We add equivalent data for { u1, u2, u3 } basis set as well. + // For every sx gate, add equiv. data for u1, u2, u3 gates. + // Note: some of our noisy simulators don't split a gate into multiple sx gates, + // hence, they cannot simulate noise at that level. + const std::string qubitOperandSuffix = gateName.substr(2); + const std::string u1GateName = "u1" + qubitOperandSuffix; + const std::string u2GateName = "u2" + qubitOperandSuffix; + const std::string u3GateName = "u3" + qubitOperandSuffix; + m_gateDurations.insert({u1GateName, 0.0}); + m_gateDurations.insert({u2GateName, gateLength}); + m_gateDurations.insert({u3GateName, 2.0 * gateLength}); + } + // Must not contain duplicates. + assert(insertOk); + } + + if (paramName == "gate_error") { + assert(paramObj["unit"].get().empty()); + const bool insertOk = + m_gateErrors.insert({gateName, paramObj["value"].get()}) + .second; + // Must not contain duplicates. + assert(insertOk); + if (gateName.rfind("sx", 0) == 0) { + const std::string qubitOperandSuffix = gateName.substr(2); + const std::string u1GateName = "u1" + qubitOperandSuffix; + const std::string u2GateName = "u2" + qubitOperandSuffix; + const std::string u3GateName = "u3" + qubitOperandSuffix; + m_gateErrors.insert({u1GateName, 0.0}); + m_gateErrors.insert({u2GateName, paramObj["value"].get()}); + m_gateErrors.insert({u3GateName, 2.0 * paramObj["value"].get()}); + } + } + } + } + } +} + +std::string +IbmqNoiseModel::getUniversalGateEquiv(xacc::quantum::Gate &in_gate) const { + if (in_gate.bits().size() == 1 && in_gate.name() != "Measure") { + // Note: rotation around Z is a noiseless *u1* operation; + // *u2* operations are those that requires a half-length rotation; + // *u3* operations are those that requires a full-length rotation. + static const std::unordered_map + SINGLE_QUBIT_GATE_MAP{{"X", "u3"}, {"Y", "u3"}, {"Z", "u1"}, + {"H", "u2"}, {"U", "u3"}, {"T", "u1"}, + {"Tdg", "u1"}, {"S", "u1"}, {"Sdg", "u1"}, + {"Rz", "u1"}, {"Rx", "u3"}, {"Ry", "u3"}}; + const auto iter = SINGLE_QUBIT_GATE_MAP.find(in_gate.name()); + // If cannot find the gate, just treat that as a noiseless u1 op. + const std::string universalGateName = + (iter == SINGLE_QUBIT_GATE_MAP.end()) ? "u1" : iter->second; + return universalGateName + std::to_string(in_gate.bits()[0]); + } + + if (in_gate.bits().size() == 2) { + return "cx" + std::to_string(in_gate.bits()[0]) + "_" + + std::to_string(in_gate.bits()[1]); + } + + return "id" + std::to_string(in_gate.bits()[0]); +} + +// Return gate time, T1, T2 +std::tuple +IbmqNoiseModel::relaxationParams(xacc::quantum::Gate &in_gate, + size_t in_qubitIdx) const { + const std::string universalGateName = getUniversalGateEquiv(in_gate); + const auto gateDurationIter = m_gateDurations.find(universalGateName); + assert(gateDurationIter != m_gateDurations.end()); + const double gateDuration = gateDurationIter->second; + const double qubitT1 = m_qubitT1[in_qubitIdx]; + const double qubitT2 = m_qubitT2[in_qubitIdx]; + return std::make_tuple(gateDuration, qubitT1, qubitT2); +} + +std::vector>> +IbmqNoiseModel::thermalRelaxationChoiMat(double in_gateTime, double in_T1, + double in_T2) const { + const double rate1 = 1.0 / in_T1; + const double pReset = 1.0 - std::exp(-in_gateTime * rate1); + + const double rate2 = 1.0 / in_T2; + const double expT2 = std::exp(-in_gateTime * rate2); + const double p0 = 1.0; + const double p1 = 0.0; + return {{1 - p1 * pReset, 0, 0, expT2}, + {0, p1 * pReset, 0, 0}, + {0, 0, p0 * pReset, 0}, + {expT2, 0, 0, 1 - p0 * pReset}}; +} + +std::vector IbmqNoiseModel::calculateDepolarizing( + xacc::quantum::Gate &in_gate, + const std::vector>> &in_relaxationError) + const { + // Compute the depolarizing channel error parameter in the + // presence of T1/T2 thermal relaxation. + // Hence we have that the depolarizing error probability + // for the composed depolarization channel is + // p = dim * (F(E_relax) - F) / (dim * F(E_relax) - 1) + const double averageThermalError = + 1.0 - averageGateFidelity(in_gate, in_relaxationError); + const std::string universalGateName = getUniversalGateEquiv(in_gate); + // Retrieve the error rate: + const auto gateErrorIter = m_gateErrors.find(universalGateName); + const double gateError = + (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; + // If the backend gate error (estimated by randomized benchmarking) is more + // than thermal relaxation error. We need to add depolarization to simulate + // the total gate error. + if (gateError > averageThermalError) { + // Model gate error entirely as depolarizing error + const double depolError = 2 * (gateError - averageThermalError) / + (2 * (1 - averageThermalError) - 1); + return {depolError}; + } + return {0.0}; +} + +double IbmqNoiseModel::averageGateFidelity( + xacc::quantum::Gate &in_gate, + const std::vector>> &in_relaxationError) + const { + // We only handle single-qubit gates for now. + if (in_gate.bits().size() == 1 && in_relaxationError.size() == 4) { + // Note: this is based on the simplified amplitude-damping channel + const double processFidelity = + (in_relaxationError[0][0].real() + in_relaxationError[0][3].real() + + in_relaxationError[3][0].real() + in_relaxationError[3][3].real()) / + 4.0; + + assert(processFidelity <= 1.0); + const double averageFidelity = (4.0 * processFidelity + 1.0) / 5.0; + return averageFidelity; + } + return 1.0; +} + +double IbmqNoiseModel::gateErrorProb(xacc::quantum::Gate &gate) const { + const auto universalGateName = getUniversalGateEquiv(gate); + const auto gateErrorIter = m_gateErrors.find(universalGateName); + return (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; +} + +std::vector +IbmqNoiseModel::getNoiseChannels(xacc::quantum::Gate &gate) const { + std::vector krausOps; + const auto noiseUtils = xacc::getService("default"); + if (gate.bits().size() == 1 && gate.name() != "Measure") { + // Amplitude damping + dephasing + const auto [gateDuration, qubitT1, qubitT2] = + relaxationParams(gate, gate.bits()[0]); + const auto relaxationError = + thermalRelaxationChoiMat(gateDuration, qubitT1, qubitT2); + + // Depolarization + const auto dpAmpl = calculateDepolarizing(gate, relaxationError); + if (!dpAmpl.empty()) { + const double probDP = dpAmpl[0]; + const std::vector>> depolErrorChoi{ + {1.0 - probDP / 2.0, 0., 0., 1.0 - probDP}, + {0., probDP / 2.0, 0., 0.}, + {0., 0., probDP / 2.0, 0.}, + {1.0 - probDP, 0., 0., 1.0 - probDP / 2.0}}; + const auto noiseUtils = xacc::getService("default"); + krausOps.emplace_back(NoiseChannelKraus(gate.bits(), noiseUtils->choiToKraus(depolErrorChoi), KrausMatBitOrder::MSB)); + } + } + // For two-qubit gates, we currently only support + // amplitude damping on both qubits (scaled by gate time). + // We don't have ability to handle multi-qubit depolarization + // in TNQVM yet. + if (gate.bits().size() == 2) { + + for (const auto &qubitIdx : gate.bits()) { + const auto [gateDuration, qubitT1, qubitT2] = + relaxationParams(gate, qubitIdx); + const auto relaxationError = + thermalRelaxationChoiMat(gateDuration, qubitT1, qubitT2); + krausOps.emplace_back(NoiseChannelKraus({qubitIdx}, noiseUtils->choiToKraus(relaxationError), KrausMatBitOrder::MSB)); + } + } + return krausOps; +} + +std::string IbmqNoiseModel::toJson() const { + // First, check if Qiskit is available, + // try to use Qiskit util if possible. + const std::string noiseModelJson = + xacc::aer::noiseModelFromBackendProperties(m_backendPropertiesJson); + if (!noiseModelJson.empty()) { + xacc::info("Qiskit generated noise model:\n" + noiseModelJson); + return noiseModelJson; + } + + // No Qiskit, create the noise model by ourselves from the backend properties. + // Aer noise model Json + nlohmann::json noiseModel; + std::vector noiseElements; + // Adds RO errors: + const auto roErrors = readoutErrors(); + for (size_t qIdx = 0; qIdx < roErrors.size(); ++qIdx) { + const auto &[meas0Prep1, meas1Prep0] = roErrors[qIdx]; + const std::vector> probs{{1 - meas1Prep0, meas1Prep0}, + {meas0Prep1, 1 - meas0Prep1}}; + nlohmann::json element; + element["type"] = "roerror"; + element["operations"] = std::vector{"measure"}; + element["probabilities"] = probs; + element["gate_qubits"] = std::vector>{{qIdx}}; + noiseElements.push_back(element); + } + + const auto noiseUtils = xacc::getService("default"); + // Add Kraus noise: + // (1) Single-qubit gate noise: + // Note: we must add noise ops for u2, u3, and cx gates: + for (size_t qIdx = 0; qIdx < roErrors.size(); ++qIdx) { + // For mapping purposes: + // U2 == Hadamard gate + // U3 == X gate + Hadamard gateU2(qIdx); + X gateU3(qIdx); + const std::unordered_map gateMap{ + {"u2", &gateU2}, {"u3", &gateU3}}; + + for (const auto &[gateName, gate] : gateMap) { + const auto errorChannels = getNoiseChannels(*gate); + nlohmann::json element; + element["type"] = "qerror"; + element["operations"] = std::vector{gateName}; + element["gate_qubits"] = std::vector>{{qIdx}}; + std::vector krausOps; + for (const auto &error : errorChannels) { + const auto krausOpMats = error.mats; + nlohmann::json instruction; + instruction["name"] = "kraus"; + instruction["qubits"] = std::vector{0}; + instruction["params"] = krausOpMats; + krausOps.emplace_back(instruction); + } + element["instructions"] = + std::vector>{krausOps}; + element["probabilities"] = std::vector{1.0}; + noiseElements.push_back(element); + } + } + + // (2) Two-qubit gate noise: + for (const auto &[qubit1, qubit2] : m_connectivity) { + // We need to add noise for both CNOT directions + // Note: the duration of them can be different, + // hence the noise channels. + CNOT cx1(std::vector{(size_t)qubit1, (size_t)qubit2}); + CNOT cx2(std::vector{(size_t)qubit2, (size_t)qubit1}); + const std::vector cxGates{&cx1, &cx2}; + for (const auto &cx : cxGates) { + const auto errorChannels = getNoiseChannels(*cx); + assert(errorChannels.size() == 2); + nlohmann::json element; + element["type"] = "qerror"; + element["operations"] = + std::vector{getUniversalGateEquiv(*cx)}; + element["gate_qubits"] = + std::vector>{cx->bits()}; + std::vector krausOps; + size_t noiseBitIdx = 0; + for (const auto &error : errorChannels) { + const auto krausOpMats = error.mats; + nlohmann::json instruction; + instruction["name"] = "kraus"; + instruction["qubits"] = std::vector{noiseBitIdx++}; + instruction["params"] = krausOpMats; + krausOps.emplace_back(instruction); + } + assert(krausOps.size() == 2); + element["instructions"] = + std::vector>{krausOps}; + element["probabilities"] = std::vector{1.0}; + noiseElements.push_back(element); + } + } + + noiseModel["errors"] = noiseElements; + return noiseModel.dump(6); +} + +std::vector IbmqNoiseModel::averageSingleQubitGateFidelity() const { + std::vector result; + // Use U3 gate fidelity: + for (size_t qId = 0; qId < m_nbQubits; ++qId) { + const std::string gateName = "u3_" + std::to_string(qId); + const auto gateErrorIter = m_gateErrors.find(gateName); + const double gateError = + (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; + result.emplace_back(1.0 - gateError); + } + return result; +} + +std::vector> +IbmqNoiseModel::averageTwoQubitGateFidelity() const { + std::vector> result; + for (const auto &[gateName, gateError] : m_gateErrors) { + if (gateName.rfind("cx", 0) == 0) { + // CNOT gate: + const std::size_t pos = gateName.find("_"); + const std::string firstArg = gateName.substr(2, pos - 2); + const std::string secondArg = gateName.substr(pos + 1); + const auto firstBit = std::atoi(firstArg.c_str()); + const auto secondBit = std::atoi(secondArg.c_str()); + result.emplace_back( + std::make_tuple(firstBit, secondBit, 1.0 - gateError)); + } + } + + return result; +} +*/ +std::string +AerAccelerator::getNativeCode(std::shared_ptr program, + const HeterogeneousMap &config) { + auto qobj_str = xacc_to_qobj->translate(program); + nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"]; + return j.dump(2); +} +} // namespace quantum +} // namespace xacc + +using namespace cppmicroservices; + +namespace { + +/** + */ +class US_ABI_LOCAL AerActivator : public BundleActivator { + +public: + AerActivator() {} + + /** + */ + void Start(BundleContext context) { + auto xt = std::make_shared(); + context.RegisterService(xt); + //context.RegisterService( + // std::make_shared()); + } + + /** + */ + void Stop(BundleContext /*context*/) {} +}; + +} // namespace + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(AerActivator) diff --git a/quantum/plugins/ibm/new_aer/aer_accelerator.hpp b/quantum/plugins/ibm/new_aer/aer_accelerator.hpp new file mode 100644 index 000000000..3510b3762 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/aer_accelerator.hpp @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2019 UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompanies this + * distribution. The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution + *License is available at https://eclipse.org/org/documents/edl-v10.php + * + * Contributors: + * Thien Nguyen - initial API and implementation + *******************************************************************************/ +#pragma once +#include "xacc.hpp" +#include + +namespace AER { +namespace Noise { +class NoiseModel; +} +} // namespace AER + +namespace xacc { +namespace quantum { + +class AerAccelerator : public Accelerator { +public: + // Identifiable interface impls + const std::string name() const override { return "new-aer"; } + const std::string description() const override { + return "XACC Simulation Accelerator based on aer library."; + } + HeterogeneousMap getProperties() override; + + // Accelerator interface impls + void initialize(const HeterogeneousMap ¶ms = {}) override; + void updateConfiguration(const HeterogeneousMap &config) override { + if (config.keyExists("shots")) { + m_shots = config.get("shots"); + m_options.insert("shots", m_shots); + } + if (config.stringExists("backend")) { + m_options.insert("backend", config.getString("backend")); + // backend changed so reinit + initialize(m_options); + } + }; + const std::vector configurationKeys() override { return {}; } + BitOrder getBitOrder() override { return BitOrder::MSB; } + void execute(std::shared_ptr buffer, + const std::shared_ptr compositeInstruction) + override; + void execute(std::shared_ptr buffer, + const std::vector> + compositeInstructions) override; + std::vector> getConnectivity() override { + return connectivity; + } + + void apply(std::shared_ptr buffer, + std::shared_ptr inst) override; + bool isInitialized() const { return initialized; } + std::string getNativeCode(std::shared_ptr program, + const HeterogeneousMap &config = {}) override; + + // ExecutionInfo implementation: + virtual xacc::HeterogeneousMap getExecutionInfo() const override { + return m_executionInfo; + } + +private: + static double calcExpectationValueZ( + const std::vector> &in_stateVec, + const std::vector &in_bits); + + static double calcExpectationValueZFromDensityMatrix( + const std::vector>> &in_densityMat, + const std::vector &in_bits); + + std::shared_ptr xacc_to_qobj; + int m_shots = 1024; + std::string m_simtype = "qasm"; + nlohmann::json noise_model; + std::vector> connectivity; + HeterogeneousMap m_options; + bool initialized = false; + std::shared_ptr noiseModelObj; + HeterogeneousMap physical_backend_properties; + // No seed + int m_seed = -1; + HeterogeneousMap m_executionInfo; +}; +} // namespace quantum +} // namespace xacc diff --git a/quantum/plugins/ibm/new_aer/aer_noise_model.hpp b/quantum/plugins/ibm/new_aer/aer_noise_model.hpp new file mode 100644 index 000000000..bf6857025 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/aer_noise_model.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include "NoiseModel.hpp" + +namespace xacc { +namespace quantum { +class IbmqNoiseModel : public NoiseModel { +public: + // Identifiable interface impls + const std::string name() const override { return "IBM"; } + const std::string description() const override { + return "Backend noise model based on IBMQ backend specifications."; + } + void initialize(const HeterogeneousMap ¶ms) override; + std::string toJson() const override; + RoErrors readoutError(size_t qubitIdx) const override { + // If this noise model has not been initialized with a backend, give zero ro + // errors. + return m_roErrors.empty() ? std::make_pair(0.0, 0.0) : m_roErrors[qubitIdx]; + } + virtual std::vector + getNoiseChannels(xacc::quantum::Gate &gate) const override; + std::vector readoutErrors() const override { return m_roErrors; } + double gateErrorProb(xacc::quantum::Gate &gate) const override; + size_t nQubits() const override { return m_nbQubits; } + std::vector averageSingleQubitGateFidelity() const override; + std::vector> + averageTwoQubitGateFidelity() const override; + +private: + // Gets the name of the equivalent universal gate. + // e.g. an Rz <=> u1; H <==> u2, etc. + std::string getUniversalGateEquiv(xacc::quantum::Gate &in_gate) const; + std::tuple + relaxationParams(xacc::quantum::Gate &in_gate, size_t in_qubitIdx) const; + std::vector + calculateDepolarizing(xacc::quantum::Gate &in_gate, + const std::vector>> + &in_relaxationError) const; + // Compute the gate fidelity given the amplitude damping noise: + double averageGateFidelity( + xacc::quantum::Gate &in_gate, + const std::vector>> &in_relaxationError) const; + + // Helper to construct the Choi matrix represents overall thermal relaxation: + // i.e. amplitude damping + dephasing. + std::vector>> + thermalRelaxationChoiMat(double in_gateTime, double in_T1, + double in_T2) const; + +private: + // Parsed parameters needed for noise model construction. + size_t m_nbQubits; + std::vector m_qubitT1; + std::vector m_qubitT2; + std::unordered_map m_gateErrors; + std::unordered_map m_gateDurations; + std::vector> m_roErrors; + std::vector> m_connectivity; + std::string m_backendPropertiesJson; +}; +} // namespace quantum +} // namespace xacc diff --git a/quantum/plugins/ibm/new_aer/manifest.json b/quantum/plugins/ibm/new_aer/manifest.json new file mode 100644 index 000000000..86521fcb7 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/manifest.json @@ -0,0 +1,6 @@ +{ + "bundle.symbolic_name" : "xacc_new_aer", + "bundle.activator" : true, + "bundle.name" : "XACC aer Simulation Accelerator", + "bundle.description" : "This bundle provides a aer Accelerator for Gate Model QC." +} \ No newline at end of file diff --git a/quantum/plugins/ibm/new_aer/tests/CMakeLists.txt b/quantum/plugins/ibm/new_aer/tests/CMakeLists.txt new file mode 100644 index 000000000..16983df22 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +# ******************************************************************************* +# Copyright (c) 2019 UT-Battelle, LLC. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Eclipse Distribution License v.10 which accompany this distribution. +# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html +# and the Eclipse Distribution License is available at +# https://eclipse.org/org/documents/edl-v10.php +# +# Contributors: +# Thien Nguyen - initial API and implementation +# *******************************************************************************/ + +add_xacc_test(NewAerAccelerator) +target_link_libraries(NewAerAcceleratorTester xacc xacc-quantum-gate) + +# Note: These tests must be disabled since the CI machine doesn't have IBMQ access. +# add_xacc_test(AerNoiseModel) +# target_link_libraries(AerNoiseModelTester xacc xacc-quantum-gate) + +# add_xacc_test(AerAcceleratorPulse) +# target_link_libraries(AerAcceleratorPulseTester xacc xacc-quantum-gate) \ No newline at end of file diff --git a/quantum/plugins/ibm/new_aer/tests/NewAerAcceleratorTester.cpp b/quantum/plugins/ibm/new_aer/tests/NewAerAcceleratorTester.cpp new file mode 100644 index 000000000..6d3ae2188 --- /dev/null +++ b/quantum/plugins/ibm/new_aer/tests/NewAerAcceleratorTester.cpp @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (c) 2019 UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompanies this + * distribution. The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution + *License is available at https://eclipse.org/org/documents/edl-v10.php + * + * Contributors: + * Thien Nguyen - initial API and implementation + *******************************************************************************/ + +#include "Accelerator.hpp" +#include "xacc.hpp" +#include +#include "xacc_observable.hpp" + +TEST(NewAerTester, checkSimple) { + auto accelerator = + xacc::getAccelerator("aer", {std::make_pair("shots", 2048)}); + auto xasmCompiler = xacc::getCompiler("xasm"); + auto ir = xasmCompiler->compile(R"(__qpu__ void bell(qbit q) { + H(q[0]); + CX(q[0], q[1]); + Measure(q[0]); + Measure(q[1]); + })", + accelerator); + + auto program = ir->getComposite("bell"); + + auto buffer = xacc::qalloc(2); + accelerator->execute(buffer, program); + + buffer->print(std::cout); + + accelerator->updateConfiguration({std::make_pair("sim-type", "statevector")}); + + buffer->resetBuffer(); + accelerator->execute(buffer, program); + buffer->print(std::cout); +} + + +TEST(NewAerTester, checkDeuteron) { + auto accelerator = + xacc::getAccelerator("aer", {std::make_pair("sim-type", "statevector")}); + auto xasmCompiler = xacc::getCompiler("xasm"); + auto ir = xasmCompiler->compile(R"(__qpu__ void ansatz(qbit q, double t) { + X(q[0]); + Ry(q[1], t); + CX(q[1], q[0]); + H(q[0]); + H(q[1]); + Measure(q[0]); + Measure(q[1]); + })", + accelerator); + + auto program = ir->getComposite("ansatz"); + // Expected results from deuteron_2qbit_xasm_X0X1 + const std::vector expectedResults{ + 0.0, -0.324699, -0.614213, -0.837166, -0.9694, + -0.996584, -0.915773, -0.735724, -0.475947, -0.164595, + 0.164595, 0.475947, 0.735724, 0.915773, 0.996584, + 0.9694, 0.837166, 0.614213, 0.324699, 0.0}; + + const auto angles = + xacc::linspace(-xacc::constants::pi, xacc::constants::pi, 20); + for (size_t i = 0; i < angles.size(); ++i) { + auto buffer = xacc::qalloc(2); + auto evaled = program->operator()({angles[i]}); + accelerator->execute(buffer, evaled); + EXPECT_NEAR(buffer->getExpectationValueZ(), expectedResults[i], 1e-6); + } +} + +#ifndef QIREE_BUILD +TEST(NewAerTester, checkDeuteronVqeH2) { + auto accelerator = + xacc::getAccelerator("aer", {std::make_pair("sim-type", "statevector")}); + + // Create the N=2 deuteron Hamiltonian + auto H_N_2 = xacc::quantum::getObservable( + "pauli", std::string("5.907 - 2.1433 X0X1 " + "- 2.1433 Y0Y1" + "+ .21829 Z0 - 6.125 Z1")); + + auto optimizer = xacc::getOptimizer("nlopt"); + xacc::qasm(R"( + .compiler xasm + .circuit deuteron_ansatz + .parameters theta + .qbit q + X(q[0]); + Ry(q[1], theta); + CNOT(q[1],q[0]); + )"); + auto ansatz = xacc::getCompiled("deuteron_ansatz"); + + // Get the VQE Algorithm and initialize it + auto vqe = xacc::getAlgorithm("vqe"); + vqe->initialize({std::make_pair("ansatz", ansatz), + std::make_pair("observable", H_N_2), + std::make_pair("accelerator", accelerator), + std::make_pair("optimizer", optimizer)}); + + // Allocate some qubits and execute + auto buffer = xacc::qalloc(2); + vqe->execute(buffer); + + // Expected result: -1.74886 + EXPECT_NEAR((*buffer)["opt-val"].as(), -1.74886, 1e-4); +} + +TEST(NewAerTester, testDeuteronVqeH3) { + auto accelerator = xacc::getAccelerator("aer", {{"sim-type", "statevector"}}); + + // Create the N=3 deuteron Hamiltonian + auto H_N_3 = xacc::quantum::getObservable( + "pauli", + std::string("5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1 + " + "9.625 - 9.625 Z2 - 3.91 X1 X2 - 3.91 Y1 Y2")); + + auto optimizer = xacc::getOptimizer("nlopt"); + + // JIT map Quil QASM Ansatz to IR + xacc::qasm(R"( + .compiler xasm + .circuit deuteron_ansatz_h3 + .parameters t0, t1 + .qbit q + X(q[0]); + exp_i_theta(q, t1, {{"pauli", "X0 Y1 - Y0 X1"}}); + exp_i_theta(q, t0, {{"pauli", "X0 Z1 Y2 - X2 Z1 Y0"}}); + )"); + auto ansatz = xacc::getCompiled("deuteron_ansatz_h3"); + + // Get the VQE Algorithm and initialize it + auto vqe = xacc::getAlgorithm("vqe"); + vqe->initialize({std::make_pair("ansatz", ansatz), + std::make_pair("observable", H_N_3), + std::make_pair("accelerator", accelerator), + std::make_pair("optimizer", optimizer)}); + + // Allocate some qubits and execute + auto buffer = xacc::qalloc(3); + vqe->execute(buffer); + + // Expected result: -2.04482 + EXPECT_NEAR((*buffer)["opt-val"].as(), -2.04482, 1e-4); +} + +#endif + +TEST(NewAerTester, testExecutionInfoStateVec) { + auto accelerator = + xacc::getAccelerator("aer", {std::make_pair("sim-type", "statevector")}); + + xacc::qasm(R"( + .compiler xasm + .circuit test_bell_exe + .qbit q + H(q[0]); + CNOT(q[0],q[1]); + )"); + auto bell = xacc::getCompiled("test_bell_exe"); + + // Allocate some qubits and execute + auto buffer = xacc::qalloc(2); + accelerator->execute(buffer, bell); + + auto exeInfo = accelerator->getExecutionInfo(); + EXPECT_GT(exeInfo.size(), 0); + auto waveFn = + accelerator->getExecutionInfo( + xacc::ExecutionInfo::WaveFuncKey); + for (const auto &elem : *waveFn) { + std::cout << elem << "\n"; + } + // 2 qubits => 4 elements + EXPECT_EQ(waveFn->size(), 4); + EXPECT_NEAR(std::abs((*waveFn)[0] - 1.0 / std::sqrt(2.0)), 0.0, 1e-9); + EXPECT_NEAR(std::abs((*waveFn)[3] - 1.0 / std::sqrt(2.0)), 0.0, 1e-9); +} + +TEST(NewAerTester, checkInitialState1) { + const std::vector> initial_states{0.0, 1.0}; + auto accelerator = xacc::getAccelerator( + "aer", {{"sim-type", "statevector"}, {"initial_state", initial_states}}); + auto xasmCompiler = xacc::getCompiler("xasm"); + auto ir = xasmCompiler->compile(R"(__qpu__ void test(qbit q) { + H(q[0]); + })", + accelerator); + + auto program = ir->getComposite("test"); + + auto buffer = xacc::qalloc(1); + accelerator->execute(buffer, program); + + auto exeInfo = accelerator->getExecutionInfo(); + EXPECT_GT(exeInfo.size(), 0); + auto waveFn = + accelerator->getExecutionInfo( + xacc::ExecutionInfo::WaveFuncKey); + for (const auto &elem : *waveFn) { + std::cout << elem << "\n"; + } + EXPECT_EQ(waveFn->size(), 2); + // Expect |-> state: |0> - |1> since we set the initial state to |1> + EXPECT_NEAR(std::abs((*waveFn)[0] - 1.0 / std::sqrt(2.0)), 0.0, 1e-9); + EXPECT_NEAR(std::abs((*waveFn)[1] + 1.0 / std::sqrt(2.0)), 0.0, 1e-9); +} + +int main(int argc, char **argv) { + xacc::Initialize(); + + ::testing::InitGoogleTest(&argc, argv); + const auto result = RUN_ALL_TESTS(); + + xacc::Finalize(); + + return result; +} diff --git a/tpls/qiskit-aer b/tpls/qiskit-aer new file mode 160000 index 000000000..5efea5735 --- /dev/null +++ b/tpls/qiskit-aer @@ -0,0 +1 @@ +Subproject commit 5efea5735433ac4914e63b0ff866c6e10e881585 From fc26536fcbf0df4251e527ea1e8cd2748224449e Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 5 Aug 2024 17:12:42 +0000 Subject: [PATCH 056/101] Optimizer plugins can ignore optimizer failure Signed-off-by: Daniel Claudino --- .../nlopt-optimizers/nlopt_optimizer.cpp | 16 +++++++++++-- .../optimizers/scipy/scipy_optimizer.cpp | 23 +++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp index c91aec2ba..3f99ae033 100644 --- a/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp +++ b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp @@ -145,6 +145,12 @@ OptResult NLOptimizer::optimize(OptFunction &function) { upperBounds = options.get>("nlopt-upper-bounds"); } + // if fails to find mininum should not throw error + bool throwError = true; + if (options.keyExists("throw-error")) { + throwError = options.get("throw-error"); + } + _opt.set_lower_bounds(lowerBounds); _opt.set_upper_bounds(upperBounds); _opt.set_maxeval(maxeval); @@ -171,10 +177,16 @@ OptResult NLOptimizer::optimize(OptFunction &function) { try { r = _opt.optimize(x, optF); } catch (std::exception &e) { - xacc::error("NLOpt failed with error code = " + std::to_string(r) + ", " + + + if (throwError) { + xacc::error("NLOpt failed with error code = " + std::to_string(r) + ", " + std::string(e.what())); - } + } else { + xacc::warning("NLOpt failed with error code = " + std::to_string(r) + ", " + + std::string(e.what())); + } + } return OptResult{optF, x}; } diff --git a/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp index 38e4760fe..b7fc7cbb4 100644 --- a/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp @@ -101,6 +101,12 @@ OptResult ScipyOptimizer::optimize(OptFunction &function) { x = std::vector(tmpx.begin(), tmpx.end()); } + // if fails to find mininum should not throw error + bool throwError = true; + if (options.keyExists("throw-error")) { + throwError = options.get("throw-error"); + } + // here the python stuff starts py::list pyInitialParams; for (const auto ¶m : x) { @@ -152,11 +158,20 @@ OptResult ScipyOptimizer::optimize(OptFunction &function) { return {optimalValue, optimizedParams}; } catch (const py::error_already_set &e) { - std::cerr << "Python error: " << e.what() << std::endl; - throw; + + if (throwError) { + xacc::error("Python error: " + std::string(e.what())); + throw; + } + return {}; + } catch (const std::exception &e) { - std::cerr << "Error: " << e.what() << std::endl; - throw; + + if (throwError) { + xacc::error("Error: " + std::string(e.what())); + throw; + } + return {}; } } } // namespace xacc From 2a95ca068f87f270d9e9965424bc5ce48d23c1a1 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 6 Aug 2024 09:39:03 -0400 Subject: [PATCH 057/101] Fix missing include directory --- xacc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/xacc/CMakeLists.txt b/xacc/CMakeLists.txt index f6c827d79..55a0ba3e4 100644 --- a/xacc/CMakeLists.txt +++ b/xacc/CMakeLists.txt @@ -94,6 +94,7 @@ endif() if(XACC_REMOTE_ACCELERATORS) target_link_libraries(xacc PRIVATE cpr::cpr) + target_include_directories(xacc PUBLIC accelerator/remote) endif() target_compile_features(xacc From 71455cc43de977ce4819ca4bccbbfae7fd6088dc Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 6 Aug 2024 09:44:32 -0400 Subject: [PATCH 058/101] Fix one last cpr issue --- quantum/plugins/ibm/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index 103829747..f9518c661 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -47,12 +47,10 @@ target_link_libraries(${LIBRARY_NAME} xacc-quantum-gate ${ANTLR_LIB} CppMicroServices - PRIVATE - cpr::cpr ) if(XACC_REMOTE_ACCELERATORS) - target_link_libraries(${LIBRARY_NAME} PRIVATE cpr) + target_link_libraries(${LIBRARY_NAME} PRIVATE cpr::cpr) endif() set(_bundle_name xacc_ibm) From 6a953fe15f9c89f1e6d8a27010b946e06fa3523c Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 6 Aug 2024 09:46:36 -0400 Subject: [PATCH 059/101] Fix iwyu issues causing mac build error --- quantum/plugins/ibm/accelerator/json/QObject.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/ibm/accelerator/json/QObject.hpp b/quantum/plugins/ibm/accelerator/json/QObject.hpp index febf574ea..31e1991df 100644 --- a/quantum/plugins/ibm/accelerator/json/QObject.hpp +++ b/quantum/plugins/ibm/accelerator/json/QObject.hpp @@ -16,11 +16,14 @@ #include "variant.hpp" #include "Json.hpp" -// #include +#include #include +#include +#include #include #include #include +#include #ifndef NLOHMANN_OPT_HELPER #define NLOHMANN_OPT_HELPER namespace nlohmann { @@ -1033,4 +1036,4 @@ inline void to_json(json &j, const xacc::ibm::QObjectResult &x) { } } // namespace nlohmann -#endif \ No newline at end of file +#endif From dc6e76746cd9b7bf545e665cf0a18898db905a6f Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 7 Aug 2024 07:15:47 -0400 Subject: [PATCH 060/101] Fix install issue from implicit json/external conflict --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cab2e9122..efc55448f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,7 +207,7 @@ endif() set(NLOHMANN_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/tpls/nlohmann/single_include) if (XACC_DEPS_EXTERNAL) - find_package(nlohmann_json 3.1) + find_package(nlohmann_json) if (nlohmann_json_FOUND) get_target_property(NLOHMANN_TARGET_INC_DIR nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) list(GET NLOHMANN_TARGET_INC_DIR 0 NLOHMANN_TARGET_INC_DIR) From 8303746de509f2347918cd14db8b463937d8e5af Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 7 Aug 2024 13:47:20 -0400 Subject: [PATCH 061/101] Echo faulty JSON when honeywell response parsing fails --- quantum/plugins/honeywell/honeywell.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/honeywell/honeywell.cpp b/quantum/plugins/honeywell/honeywell.cpp index dc7640925..3be6cab5e 100644 --- a/quantum/plugins/honeywell/honeywell.cpp +++ b/quantum/plugins/honeywell/honeywell.cpp @@ -223,12 +223,25 @@ void HoneywellAccelerator::execute( if (!retrieve_job_id.empty()) { get_job_status = get(url, "job/" + retrieve_job_id, headers); - get_job_status_json = nlohmann::json::parse(get_job_status); + try { + get_job_status_json = nlohmann::json::parse(get_job_status); + } catch (nlohmann::json::exception const &) { + std::cout << "Failed to parse response '" << get_job_status + << "' from job status " << retrieve_job_id << std::endl; + throw; + } } else { auto response = post(url, "job", j.dump(), headers); - auto response_json = nlohmann::json::parse(response); + nlohmann::json response_json; + try { + response_json = nlohmann::json::parse(response); + } catch (nlohmann::json::exception const &) { + std::cout << "Failed to parse response '" << response << "' from job" + << std::endl; + throw; + } auto job_id = response_json["job"].get(); xacc::info("Honeywell job-id: " + job_id); @@ -237,7 +250,13 @@ void HoneywellAccelerator::execute( int dots = 1; while (true) { get_job_status = get(url, "job/" + job_id, headers); - get_job_status_json = nlohmann::json::parse(get_job_status); + try { + get_job_status_json = nlohmann::json::parse(get_job_status); + } catch (nlohmann::json::exception const &) { + std::cout << "Failed to parse response '" << get_job_status + << "' from job status " << job_id << std::endl; + throw; + } if (get_job_status_json["status"].get().find("failed") != std::string::npos) { From 5eadf397a0d8a8ece79a0872886bf145dd77713b Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 9 Aug 2024 13:21:26 +0000 Subject: [PATCH 062/101] Added alternate spins ordering to chemistry Observable plugins Signed-off-by: Daniel Claudino --- python/plugins/observables/psi4_observable.py | 34 +++++++- .../plugins/observables/pyscf_observable.py | 82 +++++++++++++------ 2 files changed, 88 insertions(+), 28 deletions(-) diff --git a/python/plugins/observables/psi4_observable.py b/python/plugins/observables/psi4_observable.py index 669ca97b2..aa43c7cb2 100644 --- a/python/plugins/observables/psi4_observable.py +++ b/python/plugins/observables/psi4_observable.py @@ -13,6 +13,15 @@ def __init__(self): xacc.Observable.__init__(self) self.observable = None self.asPauli = None + self.index_map = None + + def _build_index_map(self, n_bits): + if self.index_map is None: + self.index_map = {} + for i in range(n_bits // 2): + self.index_map[i] = 2 * i + self.index_map[i + n_bits // 2] = 2 * i + 1 + return def toString(self): return self.observable.toString() @@ -137,6 +146,12 @@ def spin_block_tei(I): pos_or_neg = lambda x : ' + ' if x > 0. else ' - ' + alternate_spins = False + if 'alternate-spins' in inputParams: + alternate_spins = inputParams['alternate-spins'] + if alternate_spins: + self._build_index_map(n_active) + # --- 1-body frozen-core: Hamiltonian_fc_1body = np.zeros((n_active, n_active)) Hamiltonian_fc_1body_tmp = np.zeros((n_active, n_active)) @@ -155,7 +170,12 @@ def spin_block_tei(I): ia = MSO_frozen_list[a] Hamiltonian_fc_1body[p, q] += gmo[ia, ip, ia, iq] if abs(Hamiltonian_fc_1body[p,q]) > 1e-12: - f_str += pos_or_neg(Hamiltonian_fc_1body[p,q]) + str(abs(Hamiltonian_fc_1body[p,q])) + ' ' + str(p) + '^ ' + str(q) + f_str += pos_or_neg(Hamiltonian_fc_1body[p, q]) + str( + abs(Hamiltonian_fc_1body[p, q])) + ' ' + if alternate_spins: + f_str += str(self.index_map[p]) + '^ ' + str(self.index_map[q]) + else: + f_str += str(p) + '^ ' + str(q) # ------- 2-body frozen-core: @@ -242,7 +262,15 @@ def spin_block_tei(I): for r in range(n_active): ir = MSO_active_list[r] for ss in range(n_active): - if abs(Hamiltonian_fc_2body_tmp[p,q,r,ss]) > 1e-12: - f_str += pos_or_neg(Hamiltonian_fc_2body_tmp[p,q,r,ss]) + str(abs(Hamiltonian_fc_2body_tmp[p,q,r,ss])) + ' ' + str(p) + '^ ' + str(q) + '^ ' + str(r) + ' ' + str(ss) + if abs(Hamiltonian_fc_2body_tmp[p, q, r, ss]) > 1e-12: + f_str += pos_or_neg(Hamiltonian_fc_2body_tmp[p, q, r, ss]) + str( + abs(Hamiltonian_fc_2body_tmp[p, q, r, ss])) + ' ' + if alternate_spins: + f_str += str(self.index_map[p]) + '^ ' + f_str += str(self.index_map[q]) + '^ ' + f_str += str(self.index_map[r]) + ' ' + f_str += str(self.index_map[ss]) + else: + f_str += str(p) + '^ ' + str(q) + '^ ' + str(r) + ' ' + str(ss) self.observable = xacc.getObservable('fermion', f_str) self.asPauli = xacc.transformToPauli('jw', self.observable) \ No newline at end of file diff --git a/python/plugins/observables/pyscf_observable.py b/python/plugins/observables/pyscf_observable.py index 556bd2d7d..1aed12936 100644 --- a/python/plugins/observables/pyscf_observable.py +++ b/python/plugins/observables/pyscf_observable.py @@ -13,6 +13,15 @@ def __init__(self): xacc.Observable.__init__(self) self.observable = None self.asPauli = None + self.index_map = None + + def _build_index_map(self, n_bits): + if self.index_map is None: + self.index_map = {} + for i in range(n_bits // 2): + self.index_map[i] = 2 * i + self.index_map[i + n_bits // 2] = 2 * i + 1 + return def toString(self): return self.observable.toString() @@ -33,7 +42,7 @@ def __iter__(self): return self.asPauli.__iter__() def fromOptions(self, inputParams): - import numpy as np, sys, io, os + import numpy as np, sys from pyscf import gto, scf, dft, tddft from pyscf.lib import logger @@ -46,20 +55,20 @@ def fromOptions(self, inputParams): else: mol.build(verbose=logger.QUIET) if 'spin' in inputParams and inputParams['spin'] != 0: - mol.spin = inputParams['spin'] - scf_wfn = scf.ROHF(mol) + mol.spin = inputParams['spin'] + scf_wfn = scf.ROHF(mol) else: - scf_wfn = scf.RHF(mol) # needs to be changed for open-shells + scf_wfn = scf.RHF(mol) # needs to be changed for open-shells scf_wfn.conv_tol = 1e-8 - scf_wfn.kernel() # runs RHF calculations + scf_wfn.kernel() # runs RHF calculations E_nucl = mol.energy_nuc() # Get orbital coefficients: Ca = scf_wfn.mo_coeff Cb = scf_wfn.mo_coeff C = np.block([ - [Ca,np.zeros_like(Cb)], - [np.zeros_like(Ca),Cb] + [Ca, np.zeros_like(Cb)], + [np.zeros_like(Ca), Cb] ]) # Get the two electron integrals using MintsHelper @@ -109,7 +118,8 @@ def spin_block_tei(I): # --- th is version is safer than above (H_1b is permutted correctly if eigvecs are permutted) Hamiltonian_1body_ao = np.block([[H_core_ao, np.zeros_like(H_core_ao)], [np.zeros_like(H_core_ao), H_core_ao]]) - Hamiltonian_1body = np.einsum('ij, jk, kl -> il', C.T, Hamiltonian_1body_ao, C) + Hamiltonian_1body = np.einsum( + 'ij, jk, kl -> il', C.T, Hamiltonian_1body_ao, C) Hamiltonian_2body = gmo if 'frozen-spin-orbitals' in inputParams and 'active-spin-orbitals' in inputParams: @@ -137,7 +147,13 @@ def spin_block_tei(I): f_str = str(Hamiltonian_fc_0body) - pos_or_neg = lambda x : ' + ' if x > 0. else ' - ' + def pos_or_neg(x): return ' + ' if x > 0. else ' - ' + + alternate_spins = False + if 'alternate-spins' in inputParams: + alternate_spins = inputParams['alternate-spins'] + if alternate_spins: + self._build_index_map(n_active) # --- 1-body frozen-core: Hamiltonian_fc_1body = np.zeros((n_active, n_active)) @@ -156,13 +172,18 @@ def spin_block_tei(I): ia = MSO_frozen_list[a] Hamiltonian_fc_1body[p, q] += gmo[ia, ip, ia, iq] - if abs(Hamiltonian_fc_1body[p,q]) > 1e-12: - f_str += pos_or_neg(Hamiltonian_fc_1body[p,q]) + str(abs(Hamiltonian_fc_1body[p,q])) + ' ' + str(p) + '^ ' + str(q) - + if abs(Hamiltonian_fc_1body[p, q]) > 1e-12: + f_str += pos_or_neg(Hamiltonian_fc_1body[p, q]) + str( + abs(Hamiltonian_fc_1body[p, q])) + ' ' + if alternate_spins: + f_str += str(self.index_map[p]) + '^ ' + str(self.index_map[q]) + else: + f_str += str(p) + '^ ' + str(q) # ------- 2-body frozen-core: - Hamiltonian_fc_2body = np.zeros((n_active, n_active, n_active, n_active)) + Hamiltonian_fc_2body = np.zeros( + (n_active, n_active, n_active, n_active)) for p in range(n_active): ip = MSO_active_list[p] @@ -179,7 +200,7 @@ def spin_block_tei(I): iss = MSO_active_list[ss] #Hamiltonian_fc_2body[p,q,r,ss]= 0.25* gmo[ip,iq,ir,iss] - Hamiltonian_fc_2body[p, q, r,ss] = gmo[ip, iq, ir, iss] + Hamiltonian_fc_2body[p, q, r, ss] = gmo[ip, iq, ir, iss] #Hamiltonian_fc_2body[p,q,r,ss]= 0.25* gmo[ip,iq,iss,ir] # checking whether to reduce Hamiltonian @@ -190,15 +211,16 @@ def spin_block_tei(I): if reduce_hamiltonian: if Hamiltonian_fc_1body.shape[0] != 4: - raise NotImplementedError("Reduction only implemented for Hamiltonians with 4 spin orbitals / 2 spatial orbitals.") + raise NotImplementedError( + "Reduction only implemented for Hamiltonians with 4 spin orbitals / 2 spatial orbitals.") # Gather pieces of the Hamiltonian - h11 = Hamiltonian_fc_1body[0,0] - h22 = Hamiltonian_fc_1body[1,1] - J11 = Hamiltonian_fc_2body[0,2,0,2] - J12 = Hamiltonian_fc_2body[1,2,1,2] - J22 = Hamiltonian_fc_2body[1,3,1,3] - K12 = Hamiltonian_fc_2body[0,2,1,3] + h11 = Hamiltonian_fc_1body[0, 0] + h22 = Hamiltonian_fc_1body[1, 1] + J11 = Hamiltonian_fc_2body[0, 2, 0, 2] + J12 = Hamiltonian_fc_2body[1, 2, 1, 2] + J22 = Hamiltonian_fc_2body[1, 3, 1, 3] + K12 = Hamiltonian_fc_2body[0, 2, 1, 3] e1 = h11 + J11 e2 = h22 + 2 * J12 - K12 @@ -213,7 +235,8 @@ def spin_block_tei(I): # <10|H|01> = K12 = g4 from numpy import linalg - M = np.array([[1, 1, 1, 1], [1, -1, 1, -1], [1, 1, -1, -1], [1, -1, -1, 1]]) + M = np.array([[1, 1, 1, 1], [1, -1, 1, -1], + [1, 1, -1, -1], [1, -1, -1, 1]]) Minv = linalg.inv(M) b = np.zeros(4) @@ -235,7 +258,8 @@ def spin_block_tei(I): else: - Hamiltonian_fc_2body_tmp = 0.25 * Hamiltonian_fc_2body.transpose(0, 1, 3, 2) + Hamiltonian_fc_2body_tmp = 0.25 * \ + Hamiltonian_fc_2body.transpose(0, 1, 3, 2) for p in range(n_active): ip = MSO_active_list[p] for q in range(n_active): @@ -243,7 +267,15 @@ def spin_block_tei(I): for r in range(n_active): ir = MSO_active_list[r] for ss in range(n_active): - if abs(Hamiltonian_fc_2body_tmp[p,q,r,ss]) > 1e-12: - f_str += pos_or_neg(Hamiltonian_fc_2body_tmp[p,q,r,ss]) + str(abs(Hamiltonian_fc_2body_tmp[p,q,r,ss])) + ' ' + str(p) + '^ ' + str(q) + '^ ' + str(r) + ' ' + str(ss) + if abs(Hamiltonian_fc_2body_tmp[p, q, r, ss]) > 1e-12: + f_str += pos_or_neg(Hamiltonian_fc_2body_tmp[p, q, r, ss]) + str( + abs(Hamiltonian_fc_2body_tmp[p, q, r, ss])) + ' ' + if alternate_spins: + f_str += str(self.index_map[p]) + '^ ' + f_str += str(self.index_map[q]) + '^ ' + f_str += str(self.index_map[r]) + ' ' + f_str += str(self.index_map[ss]) + else: + f_str += str(p) + '^ ' + str(q) + '^ ' + str(r) + ' ' + str(ss) self.observable = xacc.getObservable('fermion', f_str) self.asPauli = xacc.transformToPauli('jw', self.observable) \ No newline at end of file From 8df5b163c61f4854c353978f08d82b8735c059e0 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 9 Aug 2024 15:44:05 +0000 Subject: [PATCH 063/101] Updated qsim submodule Signed-off-by: Daniel Claudino --- .gitmodules | 2 +- tpls/qsim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index ef75a52d5..6a500c473 100644 --- a/.gitmodules +++ b/.gitmodules @@ -21,7 +21,7 @@ url = https://github.com/ORNL-QCI/TriQ.git [submodule "tpls/qsim"] path = tpls/qsim - url = https://github.com/ORNL-QCI/qsim.git + url = https://github.com/quantumlib/qsim.git [submodule "tpls/pybind11"] path = tpls/pybind11 url = https://github.com/pybind/pybind11.git diff --git a/tpls/qsim b/tpls/qsim index 0afeb2bae..cf69fde84 160000 --- a/tpls/qsim +++ b/tpls/qsim @@ -1 +1 @@ -Subproject commit 0afeb2bae0981cccd3a92b75f6375ed8f6a213e4 +Subproject commit cf69fde84d99aaa8e852aacc0b410928d436dc23 From ed2246abdb3e5db91b8bdd89a54a4989efacd8e6 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 9 Aug 2024 17:27:54 +0000 Subject: [PATCH 064/101] Updated CI pipeline badge location Signed-off-by: Daniel Claudino --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c14d1a27d..f2b2ae699 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ | Branch | Status | |:-------|:-------| -|master | [![Linux CI](https://github.com/eclipse/xacc/actions/workflows/ci-linux.yml/badge.svg?branch=master)](https://github.com/eclipse/xacc/actions/workflows/ci-linux.yml) [![Mac CI](https://github.com/eclipse/xacc/actions/workflows/ci-mac.yml/badge.svg?branch=master)](https://github.com/eclipse/xacc/actions/workflows/ci-mac.yml) | -|devel | [![Linux CI](https://github.com/eclipse/xacc/actions/workflows/ci-linux.yml/badge.svg?branch=xacc-devel)](https://github.com/eclipse/xacc/actions/workflows/ci-linux.yml) [![Mac CI](https://github.com/eclipse/xacc/actions/workflows/ci-mac.yml/badge.svg?branch=xacc-devel)](https://github.com/eclipse/xacc/actions/workflows/ci-mac.yml)| +|master | [![Linux CI](https://github.com/ORNL-QCI/xacc/actions/workflows/ci-linux.yml/badge.svg?branch=master)](https://github.com/ORNL-QCI/xacc/actions/workflows/ci-linux.yml) [![Mac CI](https://github.com/ORNL-QCI/xacc/actions/workflows/ci-mac.yml/badge.svg?branch=master)](https://github.com/ORNL-QCI/xacc/actions/workflows/ci-mac.yml) | ## Language and Hardware Independent Quantum Programming Framework From 6c5733c33db6acd1c1865e7bc32612d76d95ceea Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Wed, 21 Aug 2024 16:19:17 +0000 Subject: [PATCH 065/101] Enabled IonQ noisy simulation Signed-off-by: Daniel Claudino --- quantum/plugins/ionq/ionq_accelerator.cpp | 36 ++++++++++++++----- quantum/plugins/ionq/ionq_accelerator.hpp | 13 +++---- quantum/plugins/ionq/json/ionq_program.hpp | 7 ++++ .../plugins/ionq/tests/IonQProgramTester.cpp | 9 +++-- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/quantum/plugins/ionq/ionq_accelerator.cpp b/quantum/plugins/ionq/ionq_accelerator.cpp index b2a932658..d3887cbca 100644 --- a/quantum/plugins/ionq/ionq_accelerator.cpp +++ b/quantum/plugins/ionq/ionq_accelerator.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 UT-Battelle, LLC. + * Copyright (c) 2024 UT-Battelle, LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompanies this @@ -9,6 +9,7 @@ * * Contributors: * Alexander J. McCaskey - initial API and implementation + * Daniel Claudino - Enabled access to noisy simulation *******************************************************************************/ #include "ionq_accelerator.hpp" #include @@ -33,6 +34,21 @@ HeterogeneousMap IonQAccelerator::getProperties() { return m; } +void IonQAccelerator::updateConfiguration(const HeterogeneousMap &config) { + if (config.keyExists("shots")) { + shots = config.get("shots"); + } + if (config.stringExists("backend")) { + backend = config.getString("backend"); + if (backend.find("simulator") != std::string::npos || + backend.find("sim") != std::string::npos && + backend.find(".") != std::string::npos) { + noise_model = backend.substr(backend.find(".") + 1); + backend = "simulator"; + } + } +} + void IonQAccelerator::initialize(const HeterogeneousMap ¶ms) { if (!initialized) { updateConfiguration(params); @@ -46,14 +62,15 @@ void IonQAccelerator::initialize(const HeterogeneousMap ¶ms) { auto characterizations = restClient->get(url, "/jobs", headers); auto j = nlohmann::json::parse(characterizations); // std::cout << j.dump(1) << std::endl; - // m_connectivity = j["characterizations"][0]["connectivity"].get>>(); - + // m_connectivity = + // j["characterizations"][0]["connectivity"].get>>(); + remoteUrl = url; postPath = "/jobs"; } } -// Note: IonQ don't support batching. +// Note: IonQ don't support batching. void IonQAccelerator::execute( std::shared_ptr buffer, const std::vector> circuits) { @@ -62,7 +79,6 @@ void IonQAccelerator::execute( std::make_shared(f->name(), buffer->size()); // Run each circuit RemoteAccelerator::execute(tmpBuffer, f); - // tmpBuffer->print(); buffer->appendChild(f->name(), tmpBuffer); } } @@ -74,6 +90,9 @@ const std::string IonQAccelerator::processInput( xacc::ionq::IonQProgram prog; prog.set_shots(shots); prog.set_target(backend); + if (!noise_model.empty()) { + prog.set_noise_model(noise_model); + } auto visitor = std::make_shared(); @@ -145,9 +164,11 @@ void IonQAccelerator::processResponse(std::shared_ptr buffer, std::this_thread::sleep_for(std::chrono::milliseconds(100)); } // End the color log - std::cout << "\033[0m" << "\n"; + std::cout << "\033[0m" + << "\n"; - auto results = handleExceptionRestClientGet(url, "/jobs/" + jobId + "/results", headers); + auto results = + handleExceptionRestClientGet(url, "/jobs/" + jobId + "/results", headers); std::map histogram = json::parse(results); int n = buffer->size(); @@ -220,4 +241,3 @@ void IonQAccelerator::findApiKeyInFile(std::string &apiKey, std::string &url, } } // namespace quantum } // namespace xacc - diff --git a/quantum/plugins/ionq/ionq_accelerator.hpp b/quantum/plugins/ionq/ionq_accelerator.hpp index b40b60e98..e2c4c089e 100644 --- a/quantum/plugins/ionq/ionq_accelerator.hpp +++ b/quantum/plugins/ionq/ionq_accelerator.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 UT-Battelle, LLC. + * Copyright (c) 2024 UT-Battelle, LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompanies this @@ -9,6 +9,7 @@ * * Contributors: * Alexander J. McCaskey - initial API and implementation + * Daniel Claudino - Enabled access to noisy simulation *******************************************************************************/ #ifndef QUANTUM_GATE_ACCELERATORS_IONQACCELERATOR_HPP_ #define QUANTUM_GATE_ACCELERATORS_IONQACCELERATOR_HPP_ @@ -28,14 +29,7 @@ class IonQAccelerator : public RemoteAccelerator { const std::vector> circuits) override; void initialize(const HeterogeneousMap ¶ms = {}) override; - void updateConfiguration(const HeterogeneousMap &config) override { - if (config.keyExists("shots")) { - shots = config.get("shots"); - } - if (config.stringExists("backend")) { - backend = config.getString("backend"); - } - } + void updateConfiguration(const HeterogeneousMap &config) override; const std::vector configurationKeys() override { return {"shots", "backend"}; @@ -74,6 +68,7 @@ class IonQAccelerator : public RemoteAccelerator { int shots = 1024; std::string backend = "simulator"; + std::string noise_model; std::vector> m_connectivity; bool jobIsRunning = false; diff --git a/quantum/plugins/ionq/json/ionq_program.hpp b/quantum/plugins/ionq/json/ionq_program.hpp index c91014589..3d1a5c0ce 100644 --- a/quantum/plugins/ionq/json/ionq_program.hpp +++ b/quantum/plugins/ionq/json/ionq_program.hpp @@ -77,6 +77,7 @@ namespace ionq { private: std::string lang = "json"; std::string target; + std::string noise_model = "ideal"; std::int64_t shots; Body body; @@ -89,6 +90,10 @@ namespace ionq { std::string & get_mutable_target() { return target; } void set_target(const std::string & value) { this->target = value; } + const std::string & get_noise_model() const { return noise_model; } + std::string & get_mutable_noise_model() { return noise_model; } + void set_noise_model(const std::string & value) { this->noise_model = value; } + const std::int64_t & get_shots() const { return shots; } std::int64_t & get_mutable_shots() { return shots; } void set_shots(const std::int64_t & value) { this->shots = value; } @@ -145,6 +150,7 @@ namespace nlohmann { x.set_target(j.at("target").get()); x.set_shots(j.at("shots").get()); x.set_body(j.at("input").get()); + x.set_noise_model(j.at("noise").at("model").get()); } inline void to_json(json & j, const xacc::ionq::IonQProgram & x) { @@ -153,6 +159,7 @@ namespace nlohmann { j["target"] = x.get_target(); j["shots"] = x.get_shots(); j["input"] = x.get_body(); + j["noise"] = { {"model", x.get_noise_model()} }; } } diff --git a/quantum/plugins/ionq/tests/IonQProgramTester.cpp b/quantum/plugins/ionq/tests/IonQProgramTester.cpp index 10f2e7f95..b09b22b23 100644 --- a/quantum/plugins/ionq/tests/IonQProgramTester.cpp +++ b/quantum/plugins/ionq/tests/IonQProgramTester.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 UT-Battelle, LLC. + * Copyright (c) 2024 UT-Battelle, LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompanies this @@ -9,6 +9,7 @@ * * Contributors: * Alexander J. McCaskey - initial API and implementation + * Daniel Claudino - Enabled access to noisy simulation *******************************************************************************/ #include "ionq_program.hpp" #include @@ -37,6 +38,9 @@ TEST(IonQProgramTester, checkFromJson) { "target": 1 } ] + }, + "noise": { + "model": "ideal" } })json"; using json = nlohmann::json; @@ -44,7 +48,8 @@ TEST(IonQProgramTester, checkFromJson) { auto j = json::parse(str); from_json(j, root); - std::cout << "HELLO: " << root.get_target() << "\n"; + std::cout << "HELLO: " << root.get_target() << "\nNoise model: " << root.get_noise_model() << "\n"; + json jj; From e1798627d103dca9793f717b2ea6360979930e25 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Thu, 22 Aug 2024 22:07:58 +0000 Subject: [PATCH 066/101] Removed armadillo from QITE Signed-off-by: Daniel Claudino --- .../plugins/algorithms/qite/CMakeLists.txt | 3 +- quantum/plugins/algorithms/qite/qite.cpp | 152 +++++++++--------- 2 files changed, 74 insertions(+), 81 deletions(-) diff --git a/quantum/plugins/algorithms/qite/CMakeLists.txt b/quantum/plugins/algorithms/qite/CMakeLists.txt index 456972952..97d0fa2d9 100644 --- a/quantum/plugins/algorithms/qite/CMakeLists.txt +++ b/quantum/plugins/algorithms/qite/CMakeLists.txt @@ -21,8 +21,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC . - ${CMAKE_SOURCE_DIR}/tpls/armadillo) + PUBLIC .) target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices xacc-quantum-gate) diff --git a/quantum/plugins/algorithms/qite/qite.cpp b/quantum/plugins/algorithms/qite/qite.cpp index 58e20725f..755e22f91 100644 --- a/quantum/plugins/algorithms/qite/qite.cpp +++ b/quantum/plugins/algorithms/qite/qite.cpp @@ -18,8 +18,11 @@ #include "PauliOperator.hpp" #include "Circuit.hpp" #include -#include #include +#include +#include + +using MatrixXcd = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic>; namespace { const std::complex I{0.0, 1.0}; @@ -101,11 +104,10 @@ std::vector generatePauliPermutation(int in_nbQubits) { return opsList; }; -arma::cx_mat createSMatrix(const std::vector &in_pauliOps, +Eigen::MatrixXcd createSMatrix(const std::vector &in_pauliOps, const std::vector &in_tomoExp) { const auto sMatDim = in_pauliOps.size(); - arma::cx_mat S_Mat(sMatDim, sMatDim, arma::fill::zeros); - arma::cx_vec b_Vec(sMatDim, arma::fill::zeros); + Eigen::MatrixXcd S_Mat = Eigen::MatrixXcd::Zero(sMatDim, sMatDim); const auto calcSmatEntry = [&](int in_row, int in_col) -> std::complex { @@ -144,9 +146,6 @@ using namespace xacc; namespace xacc { namespace algorithm { bool QITE::initialize(const HeterogeneousMap ¶meters) { - static std::stringstream nullStream; - // Prevents Armadillo from writing expected 'approx. solution' warnings. - arma::set_cerr_stream(nullStream); bool initializeOk = true; if (!parameters.pointerLikeExists("accelerator")) { std::cout << "'accelerator' is required.\n"; @@ -325,8 +324,8 @@ QITE::internalCalcAOps(const std::vector &pauliOps, // Calculate S matrix and b vector // i.e. set up the linear equation Sa = b const auto sMatDim = pauliOps.size(); - arma::cx_mat S_Mat(sMatDim, sMatDim, arma::fill::zeros); - arma::cx_vec b_Vec(sMatDim, arma::fill::zeros); + Eigen::MatrixXcd S_Mat = Eigen::MatrixXcd::Zero(sMatDim, sMatDim); + Eigen::VectorXcd b_Vec = Eigen::VectorXcd::Zero(sMatDim); const auto calcSmatEntry = [&](const std::vector &in_tomoExp, int in_row, @@ -373,11 +372,12 @@ QITE::internalCalcAOps(const std::vector &pauliOps, b = I * b - I * std::conj(b); // Set b_Vec b_Vec(i) = std::abs(b) > 1e-12 ? b : 0.0; + b_Vec(i) = std::abs(b) > 1e-12 ? b : 0.0; } - auto lhs = S_Mat + S_Mat.st(); + Eigen::MatrixXcd lhs = S_Mat + S_Mat.transpose(); auto rhs = -b_Vec; - arma::cx_vec a_Vec = arma::solve(lhs, rhs); + Eigen::VectorXcd a_Vec = lhs.completeOrthogonalDecomposition().solve(rhs); // Now, we have the decomposition of A observable in the basis of // all possible Pauli combinations. @@ -542,26 +542,26 @@ void QITE::execute(const std::shared_ptr buffer) const { // This serves two purposes: // (1) Validate the convergence (e.g. Trotter step size) before running via // gates. (2) Derive the circuit analytically for running. exp(-dtH) - const auto expMinusHamTerm = [](const arma::cx_mat &in_hMat, - const arma::cx_vec &in_psi, double in_dt) { - assert(in_hMat.n_rows == in_hMat.n_cols); - assert(in_hMat.n_rows == in_psi.n_elem); - arma::cx_mat hMatExp = arma::expmat(-in_dt * in_hMat); - arma::cx_vec result = hMatExp * in_psi; - const double norm = arma::norm(result, 2); + const auto expMinusHamTerm = [](const Eigen::MatrixXcd &in_hMat, + const Eigen::MatrixXcd &in_psi, double in_dt) { + assert(in_hMat.rows() == in_hMat.cols()); + assert(in_hMat.rows() == in_psi.n_elem); + Eigen::MatrixXcd hMatExp = (-in_dt * in_hMat).exp(); + Eigen::VectorXcd result = hMatExp * in_psi; + const double norm = result.norm(); result = result / norm; return std::make_pair(result, norm); }; const auto getTomographyExpVec = [](int in_nbQubits, - const arma::cx_vec &in_psi, - const arma::cx_vec &in_delta) { + const Eigen::VectorXcd &in_psi, + const Eigen::VectorXcd &in_delta) { const auto pauliOps = generatePauliPermutation(in_nbQubits); std::vector> sigmaExpectation(pauliOps.size()); std::vector> bVec(pauliOps.size()); sigmaExpectation[0] = 1.0; - bVec[0] = arma::cdot(in_delta, in_psi); + bVec[0] = in_delta.dot(in_psi); for (int i = 1; i < pauliOps.size(); ++i) { auto tomoObservable = std::make_shared(); @@ -569,33 +569,30 @@ void QITE::execute(const std::shared_ptr buffer) const { tomoObservable->fromString(pauliObsStr); assert(tomoObservable->getSubTerms().size() == 1); assert(tomoObservable->getNonIdentitySubTerms().size() == 1); - arma::cx_mat hMat(1 << in_nbQubits, 1 << in_nbQubits, - arma::fill::zeros); + Eigen::MatrixXcd hMat = Eigen::MatrixXcd::Zero(1 << in_nbQubits, 1 << in_nbQubits); const auto hamMat = tomoObservable->toDenseMatrix(in_nbQubits); - for (int i = 0; i < hMat.n_rows; ++i) { - for (int j = 0; j < hMat.n_cols; ++j) { - const int index = i * hMat.n_rows + j; + for (int i = 0; i < hMat.rows(); ++i) { + for (int j = 0; j < hMat.cols(); ++j) { + const int index = i * hMat.rows() + j; hMat(i, j) = hamMat[index]; } } - arma::cx_vec pauliApplied = hMat * in_psi; - sigmaExpectation[i] = arma::cdot(in_psi, pauliApplied); - bVec[i] = arma::cdot(in_delta, pauliApplied); + Eigen::VectorXcd pauliApplied = hMat * in_psi; + sigmaExpectation[i] = in_psi.dot(pauliApplied); + bVec[i] = in_delta.dot(pauliApplied); } return std::make_pair(sigmaExpectation, bVec); }; // Initial state - arma::cx_vec psiVec(1 << buffer->size(), arma::fill::zeros); + Eigen::VectorXcd psiVec = Eigen::VectorXcd::Zero(1 << buffer->size()); psiVec(m_initialState) = 1.0; - arma::cx_mat hMat(1 << buffer->size(), 1 << buffer->size(), - arma::fill::zeros); + Eigen::MatrixXcd hMat = Eigen::MatrixXcd::Zero(1 << buffer->size(), 1 << buffer->size()); auto identityTerm = m_observable->getIdentitySubTerm(); if (identityTerm) { - arma::cx_mat idTerm(1 << buffer->size(), 1 << buffer->size(), - arma::fill::eye); + Eigen::MatrixXcd idTerm = Eigen::MatrixXcd::Identity(1 << buffer->size(), 1 << buffer->size()); hMat += identityTerm->coefficient() * idTerm; } @@ -604,9 +601,9 @@ void QITE::execute(const std::shared_ptr buffer) const { std::dynamic_pointer_cast(hamTerm); const auto hamMat = pauliCast->toDenseMatrix(buffer->size()); - for (int i = 0; i < hMat.n_rows; ++i) { - for (int j = 0; j < hMat.n_cols; ++j) { - const int index = i * hMat.n_rows + j; + for (int i = 0; i < hMat.rows(); ++i) { + for (int j = 0; j < hMat.cols(); ++j) { + const int index = i * hMat.rows() + j; hMat(i, j) += hamMat[index]; } } @@ -615,7 +612,7 @@ void QITE::execute(const std::shared_ptr buffer) const { // Time stepping: for (int i = 0; i < m_nbSteps; ++i) { double normAfter = 0.0; - arma::cx_vec dPsiVec(1 << buffer->size(), arma::fill::zeros); + Eigen::VectorXcd dPsiVec = Eigen::VectorXcd::Zero(1 << buffer->size()); std::tie(dPsiVec, normAfter) = expMinusHamTerm(hMat, psiVec, m_dBeta); // Eq. 8, SI of https://arxiv.org/pdf/1901.07653.pdf dPsiVec = dPsiVec - psiVec; @@ -628,16 +625,16 @@ void QITE::execute(const std::shared_ptr buffer) const { pauliExpValues.emplace_back(val.real()); } - arma::cx_mat sMat = createSMatrix( + Eigen::MatrixXcd sMat = createSMatrix( generatePauliPermutation(buffer->size()), pauliExpValues); - arma::cx_vec b_Vec(bVec.size(), arma::fill::zeros); + Eigen::VectorXcd b_Vec = Eigen::VectorXcd::Zero(bVec.size()); for (int i = 0; i < bVec.size(); ++i) { b_Vec(i) = -I * bVec[i] + I * std::conj(bVec[i]); } - auto lhs = sMat + sMat.st(); + auto lhs = sMat + sMat.transpose(); auto rhs = b_Vec; - arma::cx_vec a_Vec = arma::solve(lhs, rhs); + Eigen::VectorXcd a_Vec = lhs.completeOrthogonalDecomposition().solve(rhs); const auto pauliOps = generatePauliPermutation(buffer->size()); const std::string aObsStr = [&]() { std::stringstream s; @@ -655,22 +652,20 @@ void QITE::execute(const std::shared_ptr buffer) const { std::make_shared(); updatedAham->fromString(aObsStr); const auto aHamMat = updatedAham->toDenseMatrix(buffer->size()); - arma::cx_mat aMat(1 << buffer->size(), 1 << buffer->size(), - arma::fill::zeros); + Eigen::MatrixXcd aMat = Eigen::MatrixXcd::Zero(1 << buffer->size(), 1 << buffer->size()); - for (int i = 0; i < aMat.n_rows; ++i) { - for (int j = 0; j < aMat.n_cols; ++j) { - const int index = i * aMat.n_rows + j; + for (int i = 0; i < aMat.rows(); ++i) { + for (int j = 0; j < aMat.cols(); ++j) { + const int index = i * aMat.rows() + j; aMat(i, j) = aHamMat[index]; } } // Evolve exp(-iAt) - arma::cx_mat aMatExp = arma::expmat(-I * aMat); - arma::cx_mat psiUpdate = aMatExp * psiVec; + Eigen::MatrixXcd aMatExp = (-I * aMat).exp(); + Eigen::MatrixXcd psiUpdate = aMatExp * psiVec; psiVec = psiUpdate; - const std::complex energyRaw = - arma::cdot(psiUpdate, hMat * psiUpdate); + const std::complex energyRaw = (psiUpdate.array() * (hMat * psiUpdate).array()).sum(); std::cout << "Energy = " << energyRaw << "\n"; m_energyAtStep.emplace_back(energyRaw.real()); // First step: add the approximate operator info to the buffer. @@ -767,8 +762,8 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { arange(1UL, m_energyAtStep.size() + 1, 2UL); const auto n = lanczosSteps.size(); // H and S matrices (Eq. 60) - arma::mat H(n, n, arma::fill::zeros); - arma::mat S(n, n, arma::fill::zeros); + Eigen::MatrixXcd H = Eigen::MatrixXcd::Zero(n, n); + Eigen::MatrixXcd S = Eigen::MatrixXcd::Zero(n, n); int j = 0; int k = 0; // Iterate over l and l' @@ -786,13 +781,13 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { j++; } - const auto matFieldSampling = [](const arma::mat &in_H, const arma::mat &in_S, + const auto matFieldSampling = [](const Eigen::MatrixXcd &in_H, const Eigen::MatrixXcd &in_S, const std::vector in_indexVec) { - arma::mat H(in_indexVec.size(), in_indexVec.size(), arma::fill::zeros); - arma::mat S(in_indexVec.size(), in_indexVec.size(), arma::fill::zeros); - assert(in_S.n_cols == in_H.n_cols && in_S.n_rows == in_H.n_rows); - for (size_t i = 0; i < in_H.n_rows; ++i) { - for (size_t j = 0; j < in_H.n_cols; ++j) { + Eigen::MatrixXcd H = Eigen::MatrixXcd::Zero(in_indexVec.size(), in_indexVec.size()); + Eigen::MatrixXcd S = Eigen::MatrixXcd::Zero(in_indexVec.size(), in_indexVec.size()); + assert(in_S.cols() == in_H.cols() && in_S.rows() == in_H.rows()); + for (size_t i = 0; i < in_H.rows(); ++i) { + for (size_t j = 0; j < in_H.cols(); ++j) { if (xacc::container::contains(in_indexVec, i) && xacc::container::contains(in_indexVec, j)) { const size_t rowIdx = std::distance( @@ -813,13 +808,13 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { // Regularize/stabilize H and S matrices with s and epsilon stabilization // parameters. Returns the stabilized (H, S) matrices. const auto regularizeMatrices = - [&](double s, double eps) -> std::pair { + [&](double s, double eps) -> std::pair { std::vector indexVec{0}; size_t ii = 0; size_t jj = 0; - while (ii < H.n_rows && jj < (H.n_rows - 1)) { - for (jj = ii + 1; jj < H.n_rows; ++jj) { - if (S(ii, jj) < s) { + while (ii < H.rows() && jj < (H.rows() - 1)) { + for (jj = ii + 1; jj < H.rows(); ++jj) { + if (std::abs(S(ii, jj)) < s) { indexVec.emplace_back(jj); break; } @@ -827,8 +822,8 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { ii = indexVec.back(); } - if (!xacc::container::contains(indexVec, H.n_rows - 1)) { - indexVec.emplace_back(H.n_rows - 1); + if (!xacc::container::contains(indexVec, H.rows() - 1)) { + indexVec.emplace_back(H.rows() - 1); } auto [Hnew, Snew] = matFieldSampling(H, S, indexVec); @@ -843,39 +838,38 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { } // Truncates eigenvalues if less than epsilon - arma::vec sigma; - arma::mat V; - arma::eig_sym(sigma, V, Snew); + Eigen::SelfAdjointEigenSolver eig(Snew); + Eigen::VectorXd sigma = eig.eigenvalues(); + Eigen::MatrixXcd V = eig.eigenvectors(); std::vector indexVecEig; - for (size_t i = 0; i < sigma.n_elem; ++i) { - if (sigma[i] > eps) { + for (size_t i = 0; i < sigma.size(); ++i) { + if (sigma(i) > eps) { indexVecEig.emplace_back(i); } } - const auto eigenTransform = [](const arma::mat &in_mat, - const arma::mat &in_eigenMat) { + const auto eigenTransform = [](const Eigen::MatrixXcd &in_mat, + const Eigen::MatrixXcd &in_eigenMat) { // Performs V_T * Matrix * V; // where V is the eigenvector matrix. - arma::mat result = in_eigenMat.t() * in_mat; + Eigen::MatrixXcd result = in_eigenMat.transpose() * in_mat; result = result * in_eigenMat; return result; }; - const arma::mat Snew2 = eigenTransform(Snew, V); - const arma::mat Hnew2 = eigenTransform(Hnew, V); + const Eigen::MatrixXcd Snew2 = eigenTransform(Snew, V); + const Eigen::MatrixXcd Hnew2 = eigenTransform(Hnew, V); auto [Hnew3, Snew3] = matFieldSampling(Hnew2, Snew2, indexVecEig); return std::make_pair(Hnew3, Snew3); }; auto [Hreg, Sreg] = regularizeMatrices(m_sLim, m_epsLim); - arma::cx_vec eigval; - arma::cx_mat eigvec; // Solves the generalized eigen val - arma::eig_pair(eigval, eigvec, Hreg, Sreg); + Eigen::GeneralizedSelfAdjointEigenSolver gen_eig(Hreg, Sreg); + Eigen::VectorXcd eigval = gen_eig.eigenvalues(); std::vector energies; - for (size_t i = 0; i < eigval.n_elem; ++i) { + for (size_t i = 0; i < eigval.size(); ++i) { // Energy values should be real assert(std::abs(eigval(i).imag()) < 1e-9); energies.emplace_back(eigval(i).real()); From 5e4e1fadc5380e059d964acb899e97d1c1e98fc7 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 23 Aug 2024 00:40:00 +0000 Subject: [PATCH 067/101] Fixed bugs related to retrieval of matrix/vector dimensions Signed-off-by: Daniel Claudino --- quantum/plugins/algorithms/qite/qite.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/algorithms/qite/qite.cpp b/quantum/plugins/algorithms/qite/qite.cpp index 755e22f91..a2a17ff00 100644 --- a/quantum/plugins/algorithms/qite/qite.cpp +++ b/quantum/plugins/algorithms/qite/qite.cpp @@ -381,7 +381,7 @@ QITE::internalCalcAOps(const std::vector &pauliOps, // Now, we have the decomposition of A observable in the basis of // all possible Pauli combinations. - assert(a_Vec.n_elem == pauliOps.size()); + assert(a_Vec.size() == pauliOps.size()); const std::string aObsStr = [&]() { std::stringstream s; s.precision(12); @@ -543,9 +543,9 @@ void QITE::execute(const std::shared_ptr buffer) const { // (1) Validate the convergence (e.g. Trotter step size) before running via // gates. (2) Derive the circuit analytically for running. exp(-dtH) const auto expMinusHamTerm = [](const Eigen::MatrixXcd &in_hMat, - const Eigen::MatrixXcd &in_psi, double in_dt) { + const Eigen::VectorXcd &in_psi, double in_dt) { assert(in_hMat.rows() == in_hMat.cols()); - assert(in_hMat.rows() == in_psi.n_elem); + assert(in_hMat.rows() == in_psi.size()); Eigen::MatrixXcd hMatExp = (-in_dt * in_hMat).exp(); Eigen::VectorXcd result = hMatExp * in_psi; const double norm = result.norm(); @@ -831,7 +831,7 @@ double QLanczos::calcQlanczosEnergy(const std::vector &normVec) const { // Handles an edge case where Hnew and Snew are just single-element // matrices; just returns those matrices. if (indexVec.size() == 1) { - assert(Hnew.n_elem == 1 && Snew.n_elem == 1); + assert(Hnew.size() == 1 && Snew.size() == 1); // Just returns these matrices, // no need to regularize any further. return std::make_pair(Hnew, Snew); From 12960d372ce37a942a25d173436b7b3ca1c1919c Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 23 Aug 2024 18:32:17 +0000 Subject: [PATCH 068/101] Removed armadillo from PauliOperator Signed-off-by: Daniel Claudino --- quantum/observable/pauli/CMakeLists.txt | 3 +- quantum/observable/pauli/PauliOperator.cpp | 66 +++++++++---------- .../gradient_strategies/CMakeLists.txt | 2 +- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/quantum/observable/pauli/CMakeLists.txt b/quantum/observable/pauli/CMakeLists.txt index d804b85fb..817525ff6 100644 --- a/quantum/observable/pauli/CMakeLists.txt +++ b/quantum/observable/pauli/CMakeLists.txt @@ -25,8 +25,7 @@ usFunctionGenerateBundleInit(TARGET ${LIBRARY_NAME} OUT SRC) add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories(${LIBRARY_NAME} PUBLIC - . ${CMAKE_SOURCE_DIR}/tpls/armadillo - ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src + . ${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/generated ${CMAKE_SOURCE_DIR}/tpls/taocpp diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index b921c7961..12c965043 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -18,7 +18,8 @@ #include #include "PauliOperatorLexer.h" #include "PauliListenerImpl.hpp" -#include +#include +#include namespace xacc { namespace quantum { @@ -26,17 +27,17 @@ namespace quantum { std::vector PauliOperator::to_sparse_matrix() { auto n_qubits = nQubits(); auto n_hilbert = std::pow(2, n_qubits); - using SparseMatrix = arma::SpMat>; - - SparseMatrix x(2, 2), y(2, 2), z(2, 2); - x(0, 1) = 1.0; - x(1, 0) = 1.0; - y(0, 1) = std::complex(0, -1); - y(1, 0) = std::complex(0, 1); - z(0, 0) = 1.; - z(1, 1) = -1.; - - SparseMatrix i = arma::speye(2, 2); + using SparseMatrix = Eigen::SparseMatrix>; + + SparseMatrix x(2, 2), y(2, 2), z(2, 2), i(2, 2); + x.insert(0, 1) = 1.0; + x.insert(1, 0) = 1.0; + y.insert(0, 1) = std::complex(0, -1); + y.insert(1, 0) = std::complex(0, 1); + z.insert(0, 0) = 1.; + z.insert(1, 1) = -1.; + i.insert(0, 0) = 1.0; + i.insert(1, 1) = 1.0; std::map mat_map{ {"I", i}, {"X", x}, {"Y", y}, {"Z", z}}; @@ -44,7 +45,7 @@ std::vector PauliOperator::to_sparse_matrix() { auto kron_ops = [](std::vector &ops) { auto first = ops[0]; for (int i = 1; i < ops.size(); i++) { - first = arma::kron(first, ops[i]); + first = Eigen::kroneckerProduct(first, ops[i]).eval(); } return first; }; @@ -58,15 +59,23 @@ std::vector PauliOperator::to_sparse_matrix() { if (term.second.ops().empty()) { // this was I term - auto id = arma::speye(n_hilbert, n_hilbert); + SparseMatrix id(n_hilbert, n_hilbert); + id.reserve(Eigen::VectorXi::Constant(n_hilbert, 1)); + for (std::size_t j = 0; j < n_hilbert; j++) { + id.insert(j, j) = 1.0; + } sparse_mats.push_back(id); } else { for (auto &pauli : term.second.ops()) { if (pauli.first > tensor_factor) { - auto id_qbits = pauli.first - tensor_factor; - auto id = arma::speye((int)std::pow(2, id_qbits), - (int)std::pow(2, id_qbits)); + //auto id_qbits = pauli.first - tensor_factor; + auto dim = (int)std::pow(2, pauli.first - tensor_factor); + SparseMatrix id(dim, dim); + id.reserve(Eigen::VectorXi::Constant(dim, 1)); + for (std::size_t j = 0; j < dim; j++) { + id.insert(j, j) = 1.0; + } sparse_mats.push_back(id); } @@ -74,9 +83,8 @@ std::vector PauliOperator::to_sparse_matrix() { tensor_factor = pauli.first + 1; } - for (int i = tensor_factor; i < n_qubits; i++) { - auto id = arma::speye(2, 2); - sparse_mats.push_back(id); + for (int j = tensor_factor; j < n_qubits; j++) { + sparse_mats.push_back(i); } } @@ -85,21 +93,11 @@ std::vector PauliOperator::to_sparse_matrix() { total += sp_matrix; } - // arma::vec eigval; - // arma::mat eigvec; - - // arma::sp_mat test(total.n_rows, total.n_cols); - // for (auto i = total.begin(); i != total.end(); ++i) { - // test(i.row(), i.col()) = (*i).real(); - // } - - // arma::eigs_sym(eigval, eigvec, test, 1); - - // std::cout << "EIGS:\n" << eigval << "\n"; - std::vector trips; - for (auto iter = total.begin(); iter != total.end(); ++iter) { - trips.emplace_back(iter.row(), iter.col(), *iter); + for (int k = 0; k < total.outerSize(); ++k) { + for (SparseMatrix::InnerIterator it(total, k); it; ++it) { + trips.emplace_back(it.row(), it.col(), it.value()); + } } return trips; } diff --git a/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt b/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt index 5cab05be0..620dab2ba 100644 --- a/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt +++ b/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC .) + PUBLIC . ${CMAKE_SOURCE_DIR}/tpls/armadillo) target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices PRIVATE xacc-quantum-gate) From 83c671ff91e61f428da11f4793d08b9682aad963 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 23 Aug 2024 19:07:45 +0000 Subject: [PATCH 069/101] Removed armadillo from QNG Signed-off-by: Daniel Claudino --- .../algorithms/gradient_strategies/CMakeLists.txt | 2 +- .../gradient_strategies/QuantumNaturalGradient.cpp | 13 +++++++------ .../gradient_strategies/QuantumNaturalGradient.hpp | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt b/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt index 620dab2ba..5cab05be0 100644 --- a/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt +++ b/quantum/plugins/algorithms/gradient_strategies/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC . ${CMAKE_SOURCE_DIR}/tpls/armadillo) + PUBLIC .) target_link_libraries(${LIBRARY_NAME} PUBLIC xacc CppMicroServices PRIVATE xacc-quantum-gate) diff --git a/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.cpp b/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.cpp index abc6b6aab..987d9d3c1 100644 --- a/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.cpp +++ b/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.cpp @@ -9,6 +9,7 @@ * * Contributors: * Thien Nguyen - initial API and implementation + * Daniel Claudino - Removed Armadillo *******************************************************************************/ #include "QuantumNaturalGradient.hpp" @@ -138,11 +139,11 @@ void QuantumNaturalGradient::compute(std::vector& out_dx, std::vectorcompute(rawDx, baseResults); // Solve the natural gradient equation: const auto gMat = constructMetricTensorMatrix(metricTensorResults); - arma::dvec gradients(rawDx); - arma::dvec newGrads = arma::solve(gMat, gradients); + Eigen::Map gradients(rawDx.data(), rawDx.size()); + Eigen::VectorXd newGrads = gMat.completeOrthogonalDecomposition().solve(gradients); // std::cout << "Regular gradients:\n" << gradients << "\n"; // std::cout << "Natural gradients:\n" << newGrads << "\n"; - out_dx = arma::conv_to>::from(newGrads); + out_dx = std::vector(newGrads.data(), newGrads.data() + newGrads.size()); } ObservedKernels QuantumNaturalGradient::constructMetricTensorSubCircuit(ParametrizedCircuitLayer& io_layer, @@ -217,15 +218,15 @@ ObservedKernels QuantumNaturalGradient::constructMetricTensorSubCircuit(Parametr return obsComp; } -arma::dmat QuantumNaturalGradient::constructMetricTensorMatrix(const std::vector>& in_results) +Eigen::MatrixXd QuantumNaturalGradient::constructMetricTensorMatrix(const std::vector>& in_results) { - arma::dmat gMat(m_nbParams, m_nbParams, arma::fill::zeros); + Eigen::MatrixXd gMat = Eigen::MatrixXd::Zero(m_nbParams, m_nbParams); size_t blockIdx = 0; for (auto& layer : m_layers) { const auto nbParamsInBlock = layer.paramInds.size(); // Constructs the block diagonal matrices - arma::dmat blockMat(nbParamsInBlock, nbParamsInBlock, arma::fill::zeros); + Eigen::MatrixXd blockMat = Eigen::MatrixXd::Zero(nbParamsInBlock, nbParamsInBlock); for (size_t i = 0; i < nbParamsInBlock; ++i) { diff --git a/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.hpp b/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.hpp index 7a69b5f5b..91e6175da 100644 --- a/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.hpp +++ b/quantum/plugins/algorithms/gradient_strategies/QuantumNaturalGradient.hpp @@ -9,12 +9,13 @@ * * Contributors: * Thien Nguyen - initial API and implementation + * Daniel Claudino - Removed Armadillo *******************************************************************************/ #pragma once #include "AlgorithmGradientStrategy.hpp" #include "CompositeInstruction.hpp" #include "PauliOperator.hpp" -#include +#include using namespace xacc; @@ -56,7 +57,7 @@ class QuantumNaturalGradient : public AlgorithmGradientStrategy ObservedKernels constructMetricTensorSubCircuit(ParametrizedCircuitLayer& io_layer, const std::vector& in_varNames, const std::vector& in_varVals) const; - arma::dmat constructMetricTensorMatrix(const std::vector>& in_results); + Eigen::MatrixXd constructMetricTensorMatrix(const std::vector>& in_results); private: // The *regular* gradient strategy service whose gradients will From a03ca8d33106137c11cfb9391e903fc44e20e68a Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 26 Aug 2024 22:21:07 +0000 Subject: [PATCH 070/101] Disabled iontrap plugin Signed-off-by: Daniel Claudino --- CMakeLists.txt | 1 + quantum/plugins/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f70c3b84..91ef357a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ option(XACC_ARMADILLO_INCLUDE_DIR "Path to armadillo header for mlpack optimizer option(XACC_BUILD_SCIPY "Build Scipy optimizer plugin" OFF) option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) option(XACC_BUILD_GSL "Build GNU Scientific Library optimizer plugin" OFF) +option(XACC_BUILD_IONTRAP "Build the iontrap plugin" OFF) if(XACC_BUILD_ANNEALING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index 38cc06d65..4756f3d89 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -23,7 +23,9 @@ endif() if(NOT QIREE_MINIMAL_BUILD) add_subdirectory(placement) - add_subdirectory(iontrap) + if(XACC_BUILD_IONTRAP) + add_subdirectory(iontrap) + endif() add_subdirectory(circuits) add_subdirectory(optimizers) add_subdirectory(circuit_optimizers) From 1a8fe000a19000fbd426d195ef168fad01bf7f2b Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 27 Aug 2024 14:20:28 +0000 Subject: [PATCH 071/101] Updated topdir CMakeLists.txt to handle iPOPO versions Signed-off-by: Daniel Claudino --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91ef357a7..b03050be4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,7 +255,12 @@ find_package(Python COMPONENTS Interpreter Development) if(PIP_EXISTS EQUAL "0") # we have pip, son just install ipopo message(STATUS "${BoldGreen}Installing Pelix OSGi framework.${ColorReset}") - execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ipopo) + # iPOPO 3.0 only works with python 3.10+ + if(${Python_VERSION} VERSION_GREATER_EQUAL 3.10.0) + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ipopo) + else() + execute_process(COMMAND ${Python_EXECUTABLE} -m pip install ipopo==1.0.2) + endif() else() # we dont have pip, so warn the user message(STATUS "${BoldYellow}Pelix Framework not found, but can't install via pip. Ensure you install ipopo module before using XACC Python API.${ColorReset}") From 88b8035f8137dc84648ab3c008090c8d06073f4c Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 27 Aug 2024 18:14:54 +0000 Subject: [PATCH 072/101] Cleaned cmake output Signed-off-by: Daniel Claudino --- CMakeLists.txt | 5 +++++ python/plugins/CMakeLists.txt | 6 ++++-- quantum/plugins/atos_qlm/CMakeLists.txt | 4 +++- quantum/plugins/circuits/CMakeLists.txt | 9 +++++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b03050be4..e5db65239 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,11 @@ option(XACC_BUILD_SCIPY "Build Scipy optimizer plugin" OFF) option(XACC_BUILD_ANNEALING "Build annealing libraries" OFF) option(XACC_BUILD_GSL "Build GNU Scientific Library optimizer plugin" OFF) option(XACC_BUILD_IONTRAP "Build the iontrap plugin" OFF) +option(XACC_BUILD_SCIKIT_QUANT "Build the Scikit-quant plugin" OFF) +option(XACC_BUILD_ATOS "Build the Atos QLM plugin" OFF) +option(XACC_BUILD_QFACTOR "Build the QFactor plugin" OFF) +option(XACC_BUILD_QSEARCH "Build the QSearch plugin" OFF) +option(XACC_BUILD_QRACK "Build the Qrack plugin" OFF) if(XACC_BUILD_ANNEALING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DANNEALING_ENABLED") diff --git a/python/plugins/CMakeLists.txt b/python/plugins/CMakeLists.txt index 0d1f3115d..e5cd41ca5 100644 --- a/python/plugins/CMakeLists.txt +++ b/python/plugins/CMakeLists.txt @@ -15,7 +15,7 @@ set(LIBRARY_NAME xacc-py-plugin-loader) get_filename_component(PYTHON_LIB_NAME ${Python_LIBRARIES} NAME) configure_file(py_plugin_loader.in.cpp ${CMAKE_BINARY_DIR}/python/plugins/py_plugin_loader.cpp) -message(STATUS " PYTHON: ${PYTHON_LIB_NAME}") +message(STATUS "PYTHON: ${PYTHON_LIB_NAME}") file (GLOB SRC ${CMAKE_BINARY_DIR}/python/plugins/py_plugin_loader.cpp py_plugin_loader_activator.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") @@ -52,4 +52,6 @@ endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) add_subdirectory(mitiq) -add_subdirectory(scikit-quant) \ No newline at end of file +if(XACC_BUILD_SCIKIT_QUANT) + add_subdirectory(scikit-quant) +endif() \ No newline at end of file diff --git a/quantum/plugins/atos_qlm/CMakeLists.txt b/quantum/plugins/atos_qlm/CMakeLists.txt index 8e9d9737a..9b3a56332 100644 --- a/quantum/plugins/atos_qlm/CMakeLists.txt +++ b/quantum/plugins/atos_qlm/CMakeLists.txt @@ -1 +1,3 @@ -add_subdirectory(accelerator) \ No newline at end of file +if(XACC_BUILD_ATOS) + add_subdirectory(accelerator) +endif() \ No newline at end of file diff --git a/quantum/plugins/circuits/CMakeLists.txt b/quantum/plugins/circuits/CMakeLists.txt index 032a7c72b..b674c625a 100644 --- a/quantum/plugins/circuits/CMakeLists.txt +++ b/quantum/plugins/circuits/CMakeLists.txt @@ -85,5 +85,10 @@ endif() install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) -add_subdirectory(py-qsearch) -add_subdirectory(py-qfactor) +if(XACC_BUILD_QSEARCH) + add_subdirectory(py-qsearch) +endif() + +if(XACC_BUILD_QFACTOR) + add_subdirectory(py-qfactor) +endif() \ No newline at end of file From 756a8d0758cdeeb06baee21774a60651f1a23688 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Tue, 27 Aug 2024 19:23:53 +0000 Subject: [PATCH 073/101] Renamed honeywell plugin Signed-off-by: Daniel Claudino --- quantum/plugins/CMakeLists.txt | 2 +- quantum/plugins/honeywell/manifest.json | 6 -- .../{honeywell => quantinuum}/CMakeLists.txt | 4 +- quantum/plugins/quantinuum/manifest.json | 6 ++ .../quantinuum.cpp} | 56 +++++++++---------- .../quantinuum.hpp} | 14 ++--- .../tests/CMakeLists.txt | 0 .../tests/QuantinuumAcceleratorTester.cpp} | 12 ++-- 8 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 quantum/plugins/honeywell/manifest.json rename quantum/plugins/{honeywell => quantinuum}/CMakeLists.txt (96%) create mode 100644 quantum/plugins/quantinuum/manifest.json rename quantum/plugins/{honeywell/honeywell.cpp => quantinuum/quantinuum.cpp} (90%) rename quantum/plugins/{honeywell/honeywell.hpp => quantinuum/quantinuum.hpp} (93%) rename quantum/plugins/{honeywell => quantinuum}/tests/CMakeLists.txt (100%) rename quantum/plugins/{honeywell/tests/HoneywellAcceleratorTester.cpp => quantinuum/tests/QuantinuumAcceleratorTester.cpp} (90%) diff --git a/quantum/plugins/CMakeLists.txt b/quantum/plugins/CMakeLists.txt index 4756f3d89..70b5f5f76 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -18,7 +18,7 @@ add_subdirectory(staq) if(XACC_REMOTE_ACCELERATORS) add_subdirectory(ionq) - add_subdirectory(honeywell) + add_subdirectory(quantinuum) endif() if(NOT QIREE_MINIMAL_BUILD) diff --git a/quantum/plugins/honeywell/manifest.json b/quantum/plugins/honeywell/manifest.json deleted file mode 100644 index c0426d10d..000000000 --- a/quantum/plugins/honeywell/manifest.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "bundle.symbolic_name" : "xacc_honeywell", - "bundle.activator" : true, - "bundle.name" : "Honeywell ion trap accelerator", - "bundle.description" : "" -} diff --git a/quantum/plugins/honeywell/CMakeLists.txt b/quantum/plugins/quantinuum/CMakeLists.txt similarity index 96% rename from quantum/plugins/honeywell/CMakeLists.txt rename to quantum/plugins/quantinuum/CMakeLists.txt index d54eebaf8..ec4ebbc1f 100644 --- a/quantum/plugins/honeywell/CMakeLists.txt +++ b/quantum/plugins/quantinuum/CMakeLists.txt @@ -10,7 +10,7 @@ # Contributors: # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ -set(LIBRARY_NAME xacc-honeywell) +set(LIBRARY_NAME xacc-quantinuum) file(GLOB SRC *.cpp) @@ -23,7 +23,7 @@ target_include_directories(${LIBRARY_NAME} PUBLIC .) target_link_libraries(${LIBRARY_NAME} PUBLIC xacc cpr::cpr) -set(_bundle_name xacc_honeywell) +set(_bundle_name xacc_quantinuum) set_target_properties(${LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_name} diff --git a/quantum/plugins/quantinuum/manifest.json b/quantum/plugins/quantinuum/manifest.json new file mode 100644 index 000000000..84ed27671 --- /dev/null +++ b/quantum/plugins/quantinuum/manifest.json @@ -0,0 +1,6 @@ +{ + "bundle.symbolic_name" : "xacc_quantinuum", + "bundle.activator" : true, + "bundle.name" : "Quantinuum ion trap accelerator", + "bundle.description" : "" +} diff --git a/quantum/plugins/honeywell/honeywell.cpp b/quantum/plugins/quantinuum/quantinuum.cpp similarity index 90% rename from quantum/plugins/honeywell/honeywell.cpp rename to quantum/plugins/quantinuum/quantinuum.cpp index 3be6cab5e..745323a2a 100644 --- a/quantum/plugins/honeywell/honeywell.cpp +++ b/quantum/plugins/quantinuum/quantinuum.cpp @@ -10,7 +10,7 @@ * Contributors: * Alexander J. McCaskey - initial API and implementation *******************************************************************************/ -#include "honeywell.hpp" +#include "quantinuum.hpp" #include #include @@ -78,7 +78,7 @@ std::pair need_refresh(std::vector old_key_time) { now2->tm_hour, now2->tm_min, now2->tm_sec)); } -void HoneywellAccelerator::refresh_tokens(bool force_refresh) { +void QuantinuumAccelerator::refresh_tokens(bool force_refresh) { if (!time_str.empty()) { std::vector old_time_key; auto time_split = xacc::split(time_str, '_'); @@ -96,7 +96,7 @@ void HoneywellAccelerator::refresh_tokens(bool force_refresh) { api_key = response_json["id-token"].get(); refresh_key = response_json["refresh-token"].get(); - std::ofstream out(std::string(getenv("HOME")) + "/.honeywell_config"); + std::ofstream out(std::string(getenv("HOME")) + "/.quantinuum_config"); out << "key:" << api_key << "\n"; out << "refresh:" << refresh_key << "\n"; out << "time:" << now << "\n"; @@ -106,7 +106,7 @@ void HoneywellAccelerator::refresh_tokens(bool force_refresh) { } } -void HoneywellAccelerator::initialize(const HeterogeneousMap ¶ms) { +void QuantinuumAccelerator::initialize(const HeterogeneousMap ¶ms) { if (!initialized) { searchAPIKey(api_key); @@ -144,7 +144,7 @@ void HoneywellAccelerator::initialize(const HeterogeneousMap ¶ms) { if (!xacc::container::contains(available_backends, backend)) { std::stringstream ss; ss << backend - << " is an invalid Honeywell backend or you do not have access to " + << " is an invalid Quantinuum backend or you do not have access to " "that backend.\nAvailable backends: \n"; for (const auto &name : available_backends) { ss << name << "\n"; @@ -167,19 +167,19 @@ void HoneywellAccelerator::initialize(const HeterogeneousMap ¶ms) { } } -void HoneywellAccelerator::execute( +void QuantinuumAccelerator::execute( std::shared_ptr buffer, const std::shared_ptr circuit) { if (backend.empty()) { xacc::error( - "Please specify a honeywell backend in your getAccelerator() call."); + "Please specify a quantinuum backend in your getAccelerator() call."); } auto qasm = getNativeCode(circuit); while (true) { auto backend_status = get(url, "machine/" + backend, generateRequestHeader()); auto status_J = nlohmann::json::parse(backend_status); - // xacc::info("\nHoneywell status:\n" + backend_status); + // xacc::info("\nQuantinuum status:\n" + backend_status); // If offline, terminate if (status_J["state"] == "offline") { xacc::error("Cannot run on " + backend + ", it is offline."); @@ -189,11 +189,11 @@ void HoneywellAccelerator::execute( break; } // If status = 'in maintenance', wait for a bit and try again - xacc::info("Honeywell is '" + std::string(status_J["state"]) + + xacc::info("Quantinuum is '" + std::string(status_J["state"]) + "', waiting for a bit..."); std::this_thread::sleep_for(std::chrono::seconds(60)); } - xacc::info("\nHoneywell sending qasm:\n" + qasm); + xacc::info("\nQuantinuum sending qasm:\n" + qasm); nlohmann::json j; @@ -244,7 +244,7 @@ void HoneywellAccelerator::execute( } auto job_id = response_json["job"].get(); - xacc::info("Honeywell job-id: " + job_id); + xacc::info("Quantinuum job-id: " + job_id); // Job has started, so watch for status == COMPLETED int dots = 1; @@ -260,7 +260,7 @@ void HoneywellAccelerator::execute( if (get_job_status_json["status"].get().find("failed") != std::string::npos) { - xacc::error("Honeywell job failed: " + get_job_status_json.dump(4)); + xacc::error("Quantinuum job failed: " + get_job_status_json.dump(4)); } if (get_job_status_json["status"].get() == "completed") { break; @@ -270,7 +270,7 @@ void HoneywellAccelerator::execute( dots = 1; std::stringstream ss; ss << "\033[0;32m" - << "Honeywell Job " + << "Quantinuum Job " << "\033[0;36m" << job_id << "\033[0;32m" << " Status: " << get_job_status_json["status"].get(); for (int i = 0; i < dots; i++) @@ -285,7 +285,7 @@ void HoneywellAccelerator::execute( std::cout << "\033[0m" << "\n"; - xacc::info("\nHoneywell job result json:\n" + get_job_status); + xacc::info("\nQuantinuum job result json:\n" + get_job_status); auto results = get_job_status_json["results"].begin()->get>(); for (auto &bitstring : results) { @@ -295,7 +295,7 @@ void HoneywellAccelerator::execute( return; } -void HoneywellAccelerator::execute( +void QuantinuumAccelerator::execute( std::shared_ptr buffer, const std::vector> compositeInstructions) { @@ -307,19 +307,19 @@ void HoneywellAccelerator::execute( } } -void HoneywellAccelerator::searchAPIKey(std::string &key) { +void QuantinuumAccelerator::searchAPIKey(std::string &key) { // // Search for the API Key in $HOME/.ibm_config, // // $HW_CONFIG, or in the command line argument --ibm-api-key - std::string hwConfig(std::string(getenv("HOME")) + "/.honeywell_config"); + std::string hwConfig(std::string(getenv("HOME")) + "/.quantinuum_config"); if (xacc::fileExists(hwConfig)) { findApiKeyInFile(key, hwConfig); } else { - xacc::error("Cannot find Honeywell Config file with credentials " - "(~/.honeywell_config)."); + xacc::error("Cannot find Quantinuum Config file with credentials " + "(~/.quantinuum_config)."); } } -void HoneywellAccelerator::findApiKeyInFile(std::string &apiKey, +void QuantinuumAccelerator::findApiKeyInFile(std::string &apiKey, const std::string &path) { std::ifstream stream(path); std::string contents((std::istreambuf_iterator(stream)), @@ -414,7 +414,7 @@ RestClient::get(const std::string &remoteUrl, const std::string &path, } std::string -HoneywellAccelerator::post(const std::string &_url, const std::string &path, +QuantinuumAccelerator::post(const std::string &_url, const std::string &path, const std::string &postStr, std::map headers) { std::string postResponse; @@ -452,7 +452,7 @@ HoneywellAccelerator::post(const std::string &_url, const std::string &path, } std::string -HoneywellAccelerator::get(const std::string &_url, const std::string &path, +QuantinuumAccelerator::get(const std::string &_url, const std::string &path, std::map headers, std::map extraParams) { std::string getResponse; @@ -494,7 +494,7 @@ HoneywellAccelerator::get(const std::string &_url, const std::string &path, } std::map -HoneywellAccelerator::generateRequestHeader() const { +QuantinuumAccelerator::generateRequestHeader() const { std::map headers{ {"Authorization", api_key}, {"Content-Type", "application/json"}, @@ -503,7 +503,7 @@ HoneywellAccelerator::generateRequestHeader() const { return headers; } -std::string HoneywellAccelerator::getNativeCode( +std::string QuantinuumAccelerator::getNativeCode( std::shared_ptr circuit, const HeterogeneousMap &config) { // Need to replace swaps with cnots @@ -547,14 +547,14 @@ namespace { /** */ -class US_ABI_LOCAL HoneywellActivator : public BundleActivator { +class US_ABI_LOCAL QuantinuumActivator : public BundleActivator { public: - HoneywellActivator() {} + QuantinuumActivator() {} /** */ void Start(BundleContext context) { - auto xt = std::make_shared(); + auto xt = std::make_shared(); context.RegisterService(xt); } @@ -565,4 +565,4 @@ class US_ABI_LOCAL HoneywellActivator : public BundleActivator { } // namespace -CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(HoneywellActivator) +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(QuantinuumActivator) diff --git a/quantum/plugins/honeywell/honeywell.hpp b/quantum/plugins/quantinuum/quantinuum.hpp similarity index 93% rename from quantum/plugins/honeywell/honeywell.hpp rename to quantum/plugins/quantinuum/quantinuum.hpp index 2a13d7e6c..8a55a6ab3 100644 --- a/quantum/plugins/honeywell/honeywell.hpp +++ b/quantum/plugins/quantinuum/quantinuum.hpp @@ -10,8 +10,8 @@ * Contributors: * Alexander J. McCaskey - initial API and implementation *******************************************************************************/ -#ifndef XACC_HONEYWELL_ACCELERATOR_HPP_ -#define XACC_HONEYWELL_ACCELERATOR_HPP_ +#ifndef XACC_QUANTINUUM_ACCELERATOR_HPP_ +#define XACC_QUANTINUUM_ACCELERATOR_HPP_ #include "InstructionIterator.hpp" #include "Accelerator.hpp" @@ -56,7 +56,7 @@ std::string integral_to_binary_string(T byte, IS_INTEGRAL(T)) { std::string hex_string_to_binary_string(std::string hex); -class HoneywellAccelerator : public Accelerator { +class QuantinuumAccelerator : public Accelerator { public: void initialize(const HeterogeneousMap ¶ms = {}) override; void updateConfiguration(const HeterogeneousMap &config) override { @@ -76,10 +76,10 @@ class HoneywellAccelerator : public Accelerator { } const std::string getSignature() override { - return "honeywell"; + return "quantinuum"; } - const std::string name() const override { return "honeywell"; } + const std::string name() const override { return "quantinuum"; } const std::string description() const override { return ""; } @@ -94,10 +94,10 @@ class HoneywellAccelerator : public Accelerator { const HeterogeneousMap &config = {}) override; bool isRemote() override { return true; } - HoneywellAccelerator() + QuantinuumAccelerator() : Accelerator(), restClient(std::make_shared()) {} - virtual ~HoneywellAccelerator() {} + virtual ~QuantinuumAccelerator() {} private: void refresh_tokens(bool force = false); diff --git a/quantum/plugins/honeywell/tests/CMakeLists.txt b/quantum/plugins/quantinuum/tests/CMakeLists.txt similarity index 100% rename from quantum/plugins/honeywell/tests/CMakeLists.txt rename to quantum/plugins/quantinuum/tests/CMakeLists.txt diff --git a/quantum/plugins/honeywell/tests/HoneywellAcceleratorTester.cpp b/quantum/plugins/quantinuum/tests/QuantinuumAcceleratorTester.cpp similarity index 90% rename from quantum/plugins/honeywell/tests/HoneywellAcceleratorTester.cpp rename to quantum/plugins/quantinuum/tests/QuantinuumAcceleratorTester.cpp index 1c5456e86..049437680 100644 --- a/quantum/plugins/honeywell/tests/HoneywellAcceleratorTester.cpp +++ b/quantum/plugins/quantinuum/tests/QuantinuumAcceleratorTester.cpp @@ -13,9 +13,9 @@ #include "xacc.hpp" #include -TEST(HoneywellAcceleratorTester, checkSimple) { +TEST(QuantinuumAcceleratorTester, checkSimple) { xacc::set_verbose(true); - auto accelerator = xacc::getAccelerator("honeywell:H1-1SC"); + auto accelerator = xacc::getAccelerator("quantinuum:H1-1SC"); auto xasmCompiler = xacc::getCompiler("xasm"); auto ir = xasmCompiler->compile(R"(__qpu__ void bell(qbit q) { H(q[0]); @@ -33,9 +33,9 @@ TEST(HoneywellAcceleratorTester, checkSimple) { buffer->print(std::cout); } -TEST(HoneywellAcceleratorTester, checkConditionalTeleport) { +TEST(QuantinuumAcceleratorTester, checkConditionalTeleport) { xacc::set_verbose(true); - auto accelerator = xacc::getAccelerator("honeywell:H1-1SC"); + auto accelerator = xacc::getAccelerator("quantinuum:H1-1SC"); auto buffer = xacc::qalloc(3); auto xasmCompiler = xacc::getCompiler("xasm"); auto ir = xasmCompiler->compile(R"(__qpu__ void teleport(qbit q) { @@ -68,9 +68,9 @@ TEST(HoneywellAcceleratorTester, checkConditionalTeleport) { buffer->print(); } -TEST(HoneywellAcceleratorTester, checkConditionalIQPE) { +TEST(QuantinuumAcceleratorTester, checkConditionalIQPE) { xacc::set_verbose(true); - auto accelerator = xacc::getAccelerator("honeywell:H1-1SC"); + auto accelerator = xacc::getAccelerator("quantinuum:H1-1SC"); auto buffer = xacc::qalloc(3); auto xasmCompiler = xacc::getCompiler("xasm"); // Make sure we can validate it. From 6edbc8198411d2b3c5487e92e35c14dedf2d1d0a Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Mon, 9 Sep 2024 18:29:44 +0000 Subject: [PATCH 074/101] Enabled open shells in the chemistry observables Signed-off-by: Daniel Claudino --- python/plugins/observables/psi4_observable.py | 12 +++++- .../plugins/observables/pyscf_observable.py | 40 ++++++++++++++----- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/python/plugins/observables/psi4_observable.py b/python/plugins/observables/psi4_observable.py index aa43c7cb2..5fb619f13 100644 --- a/python/plugins/observables/psi4_observable.py +++ b/python/plugins/observables/psi4_observable.py @@ -53,8 +53,16 @@ def fromOptions(self, inputParams): 'mp2_type':'conv', 'e_convergence': 1e-8, 'd_convergence': 1e-8} - if moleculeGeom.multiplicity() > 1: - options['reference'] = 'rohf' + + if 'reference' in inputParams: + options['reference'] = inputParams['reference'].lower() + + if options['reference'] == 'uhf': + is_restricted_ref = False + + if moleculeGeom.multiplicity() > 1 and options['reference'] == 'rhf': + xacc.error('Spin multiplicity needs to be one for RHF.') + psi4.set_options(options) scf_e, scf_wfn = psi4.energy('scf', return_wfn=True) E_nucl = moleculeGeom.nuclear_repulsion_energy() diff --git a/python/plugins/observables/pyscf_observable.py b/python/plugins/observables/pyscf_observable.py index 1aed12936..29e705d51 100644 --- a/python/plugins/observables/pyscf_observable.py +++ b/python/plugins/observables/pyscf_observable.py @@ -50,22 +50,45 @@ def fromOptions(self, inputParams): sys.argv = [''] mol.atom = inputParams['geometry'] mol.basis = inputParams['basis'] + + if 'charge' in inputParams: + mol.charge = inputParams['charge'] + + if 'spin' in inputParams: + mol.spin = inputParams['spin'] + if 'verbose' in inputParams and inputParams['verbose']: mol.build() else: mol.build(verbose=logger.QUIET) - if 'spin' in inputParams and inputParams['spin'] != 0: - mol.spin = inputParams['spin'] - scf_wfn = scf.ROHF(mol) + + is_restricted_ref = True + if 'reference' in inputParams: + if inputParams['reference'] == 'ROHF' or inputParams['reference'] == 'rohf': + scf_wfn = scf.ROHF(mol) + elif inputParams['reference'] == 'UHF' or inputParams['reference'] == 'uhf': + scf_wfn = scf.UHF(mol) + is_restricted_ref = False + elif inputParams['reference'] == 'RHF' or inputParams['reference'] == 'rhf': + if mol.spin != 0: + xacc.error('Spin needs to be zero for RHF.') + scf_wfn = scf.RHF(mol) else: - scf_wfn = scf.RHF(mol) # needs to be changed for open-shells + if mol.spin != 0: + xacc.error('Spin needs to be zero for RHF.') + scf_wfn = scf.RHF(mol) + scf_wfn.conv_tol = 1e-8 - scf_wfn.kernel() # runs RHF calculations + scf_wfn.kernel() E_nucl = mol.energy_nuc() # Get orbital coefficients: - Ca = scf_wfn.mo_coeff - Cb = scf_wfn.mo_coeff + if is_restricted_ref: + Ca = scf_wfn.mo_coeff + Cb = scf_wfn.mo_coeff + else: + Ca = scf_wfn.mo_coeff[0, :, :] + Cb = scf_wfn.mo_coeff[1, :, :] C = np.block([ [Ca, np.zeros_like(Cb)], [np.zeros_like(Ca), Cb] @@ -157,7 +180,6 @@ def pos_or_neg(x): return ' + ' if x > 0. else ' - ' # --- 1-body frozen-core: Hamiltonian_fc_1body = np.zeros((n_active, n_active)) - Hamiltonian_fc_1body_tmp = np.zeros((n_active, n_active)) for p in range(n_active): ip = MSO_active_list[p] @@ -166,12 +188,12 @@ def pos_or_neg(x): return ' + ' if x > 0. else ' - ' iq = MSO_active_list[q] Hamiltonian_fc_1body[p, q] = Hamiltonian_1body[ip, iq] - #Hamiltonian_fc_1body_tmp[p,q] = Hamiltonian_1body[ip,iq] for a in range(n_frozen): ia = MSO_frozen_list[a] Hamiltonian_fc_1body[p, q] += gmo[ia, ip, ia, iq] + if abs(Hamiltonian_fc_1body[p, q]) > 1e-12: f_str += pos_or_neg(Hamiltonian_fc_1body[p, q]) + str( abs(Hamiltonian_fc_1body[p, q])) + ' ' From ef2424724d91efa4cf762c97d18b554423a01515 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 13 Sep 2024 13:18:51 +0000 Subject: [PATCH 075/101] Added knobs to control tolerance in NLOpt Signed-off-by: Daniel Claudino --- .../nlopt-optimizers/nlopt_optimizer.cpp | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp index 3f99ae033..c1ed058c2 100644 --- a/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp +++ b/quantum/plugins/optimizers/nlopt-optimizers/nlopt_optimizer.cpp @@ -59,7 +59,7 @@ OptResult NLOptimizer::optimize(OptFunction &function) { auto dim = function.dimensions(); nlopt::algorithm algo = nlopt::algorithm::LN_COBYLA; - double tol = 1e-6; + double tol = 1e-6, absFTol = 1e-6, relFTol = 1e-6, absXTol = 1e-6, relXTol = 1e-6; int maxeval = 1000; bool maximize = false; @@ -98,6 +98,34 @@ OptResult NLOptimizer::optimize(OptFunction &function) { xacc::info("[NLOpt] function tolerance set to " + std::to_string(tol)); } + if (options.keyExists("absolute-ftol")) { + absFTol = options.get("absolute-ftol"); + xacc::info("[NLOpt] absolute function tolerance set to " + std::to_string(absFTol)); + } else { + absFTol = tol; + } + + if (options.keyExists("relative-ftol")) { + relFTol = options.get("relative-ftol"); + xacc::info("[NLOpt] relative function tolerance set to " + std::to_string(relFTol)); + } else { + relFTol = tol; + } + + if (options.keyExists("absolute-xtol")) { + absXTol = options.get("absolute-xtol"); + xacc::info("[NLOpt] absolute parameter tolerance set to " + std::to_string(absXTol)); + } else { + absXTol = tol; + } + + if (options.keyExists("relative-xtol")) { + relXTol = options.get("relative-xtol"); + xacc::info("[NLOpt] relative parameter tolerance set to " + std::to_string(relXTol)); + } else { + relXTol = tol; + } + if (options.keyExists("maxeval")) { maxeval = options.get("maxeval"); xacc::info("[NLOpt] max function evaluations set to " + @@ -154,7 +182,10 @@ OptResult NLOptimizer::optimize(OptFunction &function) { _opt.set_lower_bounds(lowerBounds); _opt.set_upper_bounds(upperBounds); _opt.set_maxeval(maxeval); - _opt.set_ftol_rel(tol); + _opt.set_ftol_rel(relFTol); + _opt.set_ftol_abs(absFTol); + _opt.set_xtol_rel(relXTol); + _opt.set_xtol_abs(absXTol); if (options.keyExists("stopval")) { const double stopVal = options.get("stopval"); From e116c0e6aee63f8d25eb4592f4b9e7de25d86503 Mon Sep 17 00:00:00 2001 From: Daniel Claudino Date: Fri, 13 Sep 2024 17:48:44 +0000 Subject: [PATCH 076/101] Revamped Aer plugin Signed-off-by: Daniel Claudino --- quantum/plugins/ibm/CMakeLists.txt | 2 +- quantum/plugins/ibm/aer/CMakeLists.txt | 29 +- .../ibm/aer/accelerator/aer_accelerator.cpp | 1075 ----- .../ibm/{new_aer => aer}/aer_accelerator.cpp | 45 +- .../aer/{accelerator => }/aer_accelerator.hpp | 0 .../aer/{accelerator => }/aer_noise_model.hpp | 0 quantum/plugins/ibm/aer/py-aer/CMakeLists.txt | 43 - .../ibm/aer/py-aer/aer_python_adapter.hpp | 14 - .../ibm/aer/py-aer/aer_python_adapter.in.cpp | 161 - quantum/plugins/ibm/aer/src/LICENSE.txt | 203 - .../aer/src/controllers/aer_controller.hpp | 2003 ---------- .../src/controllers/controller_execute.hpp | 45 - .../ibm/aer/src/framework/avx2_detect.hpp | 97 - .../ibm/aer/src/framework/blas_protos.hpp | 163 - .../plugins/ibm/aer/src/framework/circuit.hpp | 518 --- .../plugins/ibm/aer/src/framework/creg.hpp | 256 -- .../plugins/ibm/aer/src/framework/json.hpp | 320 -- .../ibm/aer/src/framework/json_parser.hpp | 88 - .../aer/src/framework/linalg/almost_equal.hpp | 55 - .../aer/src/framework/linalg/eigensystem.hpp | 101 - .../framework/linalg/enable_if_numeric.hpp | 38 - .../ibm/aer/src/framework/linalg/linalg.hpp | 30 - .../linalg/linops/linops_aer_vector.hpp | 130 - .../framework/linalg/linops/linops_array.hpp | 130 - .../linalg/linops/linops_generic.hpp | 119 - .../framework/linalg/linops/linops_json.hpp | 242 -- .../framework/linalg/linops/linops_map.hpp | 190 - .../framework/linalg/linops/linops_matrix.hpp | 144 - .../linalg/linops/linops_unordered_map.hpp | 194 - .../framework/linalg/linops/linops_vector.hpp | 172 - .../aer/src/framework/linalg/matrix_utils.hpp | 22 - .../linalg/matrix_utils/matrix_defs.hpp | 395 -- .../linalg/matrix_utils/smatrix_defs.hpp | 318 -- .../linalg/matrix_utils/vmatrix_defs.hpp | 375 -- .../ibm/aer/src/framework/linalg/square.hpp | 208 - .../ibm/aer/src/framework/linalg/vector.hpp | 408 -- .../aer/src/framework/linalg/vector_json.hpp | 58 - .../plugins/ibm/aer/src/framework/matrix.hpp | 834 ---- .../ibm/aer/src/framework/noise_utils.hpp | 140 - .../ibm/aer/src/framework/operations.hpp | 1415 ------- .../plugins/ibm/aer/src/framework/opset.hpp | 284 -- .../ibm/aer/src/framework/pybind_basics.hpp | 205 - .../ibm/aer/src/framework/pybind_casts.hpp | 75 - .../ibm/aer/src/framework/pybind_json.hpp | 313 -- .../ibm/aer/src/framework/python_parser.hpp | 154 - .../plugins/ibm/aer/src/framework/qobj.hpp | 189 - .../aer/src/framework/results/data/data.hpp | 253 -- .../src/framework/results/data/metadata.hpp | 136 - .../results/data/mixins/data_cdict.hpp | 66 - .../results/data/mixins/data_cmatrix.hpp | 103 - .../results/data/mixins/data_creg.hpp | 57 - .../results/data/mixins/data_cvector.hpp | 75 - .../results/data/mixins/data_json.hpp | 66 - .../results/data/mixins/data_mps.hpp | 63 - .../results/data/mixins/data_rdict.hpp | 71 - .../results/data/mixins/data_rvalue.hpp | 72 - .../results/data/mixins/data_rvector.hpp | 71 - .../results/data/mixins/pybind_data_cdict.hpp | 53 - .../data/mixins/pybind_data_cmatrix.hpp | 65 - .../results/data/mixins/pybind_data_creg.hpp | 51 - .../data/mixins/pybind_data_cvector.hpp | 57 - .../results/data/mixins/pybind_data_json.hpp | 53 - .../results/data/mixins/pybind_data_mps.hpp | 69 - .../results/data/mixins/pybind_data_rdict.hpp | 55 - .../data/mixins/pybind_data_rvalue.hpp | 55 - .../data/mixins/pybind_data_rvector.hpp | 55 - .../framework/results/data/pybind_data.hpp | 56 - .../results/data/pybind_metadata.hpp | 42 - .../results/data/subtypes/accum_data.hpp | 81 - .../results/data/subtypes/average_data.hpp | 114 - .../results/data/subtypes/data_map.hpp | 220 - .../results/data/subtypes/list_data.hpp | 71 - .../results/data/subtypes/pybind_data_map.hpp | 76 - .../results/data/subtypes/pybind_subtypes.hpp | 69 - .../results/data/subtypes/single_data.hpp | 80 - .../framework/results/experiment_result.hpp | 105 - .../framework/results/legacy/average_data.hpp | 251 -- .../results/legacy/average_snapshot.hpp | 134 - .../results/legacy/data_container.hpp | 249 -- .../framework/results/legacy/pershot_data.hpp | 95 - .../results/legacy/pershot_snapshot.hpp | 115 - .../framework/results/legacy/pybind_data.hpp | 414 -- .../results/legacy/snapshot_data.hpp | 304 -- .../src/framework/results/pybind_result.hpp | 119 - .../ibm/aer/src/framework/results/result.hpp | 106 - quantum/plugins/ibm/aer/src/framework/rng.hpp | 112 - .../ibm/aer/src/framework/stl_ostream.hpp | 121 - .../plugins/ibm/aer/src/framework/types.hpp | 60 - .../plugins/ibm/aer/src/framework/utils.hpp | 1344 ------- .../ibm/aer/src/misc/clang_omp_symbols.hpp | 340 -- .../ibm/aer/src/misc/common_macros.hpp | 22 - .../ibm/aer/src/misc/gcc_omp_symbols.hpp | 116 - quantum/plugins/ibm/aer/src/misc/hacks.hpp | 85 - quantum/plugins/ibm/aer/src/misc/warnings.hpp | 47 - .../plugins/ibm/aer/src/misc/wrap_thrust.hpp | 49 - .../plugins/ibm/aer/src/noise/noise_model.hpp | 1056 ----- .../ibm/aer/src/noise/quantum_error.hpp | 397 -- .../ibm/aer/src/noise/readout_error.hpp | 121 - .../ibm/aer/src/open_pulse/CMakeLists.txt | 19 - .../aer/src/open_pulse/eval_hamiltonian.hpp | 108 - .../ibm/aer/src/open_pulse/iterators.hpp | 91 - .../plugins/ibm/aer/src/open_pulse/log.hpp | 100 - .../aer/src/open_pulse/numeric_integrator.cpp | 272 -- .../aer/src/open_pulse/numeric_integrator.hpp | 56 - .../ibm/aer/src/open_pulse/ordered_map.hpp | 117 - .../ibm/aer/src/open_pulse/pulse_utils.cpp | 172 - .../ibm/aer/src/open_pulse/pulse_utils.hpp | 100 - .../src/open_pulse/pulse_utils_bindings.cpp | 54 - .../ibm/aer/src/open_pulse/python_to_cpp.hpp | 489 --- .../aer/src/open_pulse/test_python_to_cpp.cpp | 77 - .../aer/src/open_pulse/test_python_to_cpp.hpp | 57 - .../plugins/ibm/aer/src/open_pulse/types.hpp | 27 - .../plugins/ibm/aer/src/open_pulse/zspmv.cpp | 172 - .../plugins/ibm/aer/src/open_pulse/zspmv.hpp | 53 - .../density_matrix/densitymatrix.hpp | 498 --- .../density_matrix/densitymatrix_state.hpp | 2059 ---------- .../density_matrix/densitymatrix_thrust.hpp | 1640 -------- .../extended_stabilizer/ch_runner.hpp | 797 ---- .../chlib/chstabilizer.hpp | 1070 ----- .../extended_stabilizer/chlib/core.hpp | 558 --- .../extended_stabilizer_state.hpp | 1091 ----- .../simulators/extended_stabilizer/gates.hpp | 246 -- .../matrix_product_state.hpp | 1159 ------ .../matrix_product_state_internal.cpp | 1899 --------- .../matrix_product_state_internal.hpp | 576 --- .../matrix_product_state_tensor.hpp | 695 ---- .../simulators/matrix_product_state/svd.cpp | 592 --- .../simulators/matrix_product_state/svd.hpp | 48 - .../simulators/stabilizer/binary_vector.hpp | 300 -- .../src/simulators/stabilizer/clifford.hpp | 451 --- .../aer/src/simulators/stabilizer/pauli.hpp | 130 - .../stabilizer/stabilizer_state.hpp | 911 ----- .../plugins/ibm/aer/src/simulators/state.hpp | 692 ---- .../ibm/aer/src/simulators/state_chunk.hpp | 2559 ------------ .../simulators/statevector/chunk/chunk.hpp | 473 --- .../statevector/chunk/chunk_container.hpp | 1073 ----- .../statevector/chunk/chunk_manager.hpp | 453 --- .../chunk/cuStateVec_chunk_container.hpp | 871 ---- .../statevector/chunk/cuda_kernels.hpp | 360 -- .../chunk/device_chunk_container.hpp | 1257 ------ .../chunk/host_chunk_container.hpp | 278 -- .../statevector/chunk/thrust_kernels.hpp | 2776 ------------- .../src/simulators/statevector/indexes.hpp | 328 -- .../simulators/statevector/qubitvector.hpp | 2329 ----------- .../statevector/qubitvector_thrust.hpp | 3544 ----------------- .../src/simulators/statevector/qv_avx2.cpp | 1278 ------ .../src/simulators/statevector/qv_avx2.hpp | 45 - .../statevector/statevector_state.hpp | 2379 ----------- .../simulators/statevector/transformer.hpp | 378 -- .../statevector/transformer_avx2.hpp | 102 - .../superoperator/superoperator.hpp | 186 - .../superoperator/superoperator_state.hpp | 583 --- .../superoperator/superoperator_thrust.hpp | 186 - .../src/simulators/unitary/unitary_state.hpp | 880 ---- .../src/simulators/unitary/unitarymatrix.hpp | 334 -- .../unitary/unitarymatrix_thrust.hpp | 369 -- .../ibm/aer/src/transpile/basic_opts.hpp | 80 - .../ibm/aer/src/transpile/cacheblocking.hpp | 903 ----- .../ibm/aer/src/transpile/circuitopt.hpp | 59 - .../plugins/ibm/aer/src/transpile/fusion.hpp | 1060 ----- .../aer/tests/AerAcceleratorPulseTester.cpp | 47 - .../ibm/aer/tests/AerAcceleratorTester.cpp | 2 + .../ibm/aer/tests/AerNoiseModelTester.cpp | 64 - quantum/plugins/ibm/new_aer/CMakeLists.txt | 88 - .../plugins/ibm/new_aer/aer_accelerator.hpp | 94 - .../plugins/ibm/new_aer/aer_noise_model.hpp | 63 - quantum/plugins/ibm/new_aer/manifest.json | 6 - .../plugins/ibm/new_aer/tests/CMakeLists.txt | 22 - .../new_aer/tests/NewAerAcceleratorTester.cpp | 226 -- 169 files changed, 41 insertions(+), 63187 deletions(-) delete mode 100644 quantum/plugins/ibm/aer/accelerator/aer_accelerator.cpp rename quantum/plugins/ibm/{new_aer => aer}/aer_accelerator.cpp (97%) rename quantum/plugins/ibm/aer/{accelerator => }/aer_accelerator.hpp (100%) rename quantum/plugins/ibm/aer/{accelerator => }/aer_noise_model.hpp (100%) delete mode 100644 quantum/plugins/ibm/aer/py-aer/CMakeLists.txt delete mode 100644 quantum/plugins/ibm/aer/py-aer/aer_python_adapter.hpp delete mode 100644 quantum/plugins/ibm/aer/py-aer/aer_python_adapter.in.cpp delete mode 100644 quantum/plugins/ibm/aer/src/LICENSE.txt delete mode 100755 quantum/plugins/ibm/aer/src/controllers/aer_controller.hpp delete mode 100755 quantum/plugins/ibm/aer/src/controllers/controller_execute.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/avx2_detect.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/blas_protos.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/circuit.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/creg.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/json.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/json_parser.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/almost_equal.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/linalg/eigensystem.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/enable_if_numeric.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linalg.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_aer_vector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_array.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_generic.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_json.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_map.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_matrix.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_unordered_map.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_vector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/matrix_defs.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/smatrix_defs.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/vmatrix_defs.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/square.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/vector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/linalg/vector_json.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/matrix.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/noise_utils.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/operations.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/opset.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/pybind_basics.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/pybind_casts.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/pybind_json.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/python_parser.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/qobj.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/data.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/metadata.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cdict.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cmatrix.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_creg.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cvector.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_json.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_mps.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rdict.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvalue.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cdict.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cmatrix.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_creg.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cvector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_json.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_mps.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rdict.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvalue.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvector.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/pybind_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/pybind_metadata.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/accum_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/average_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/data_map.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/list_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/pybind_data_map.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/pybind_subtypes.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/data/subtypes/single_data.hpp delete mode 100644 quantum/plugins/ibm/aer/src/framework/results/experiment_result.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/average_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/average_snapshot.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/data_container.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/pershot_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/pershot_snapshot.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/pybind_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/legacy/snapshot_data.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/pybind_result.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/results/result.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/rng.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/stl_ostream.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/types.hpp delete mode 100755 quantum/plugins/ibm/aer/src/framework/utils.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/clang_omp_symbols.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/common_macros.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/gcc_omp_symbols.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/hacks.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/warnings.hpp delete mode 100644 quantum/plugins/ibm/aer/src/misc/wrap_thrust.hpp delete mode 100644 quantum/plugins/ibm/aer/src/noise/noise_model.hpp delete mode 100644 quantum/plugins/ibm/aer/src/noise/quantum_error.hpp delete mode 100644 quantum/plugins/ibm/aer/src/noise/readout_error.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/CMakeLists.txt delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/eval_hamiltonian.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/iterators.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/log.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/numeric_integrator.cpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/numeric_integrator.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/ordered_map.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/pulse_utils.cpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/pulse_utils.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/pulse_utils_bindings.cpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/python_to_cpp.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/test_python_to_cpp.cpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/test_python_to_cpp.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/types.hpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/zspmv.cpp delete mode 100644 quantum/plugins/ibm/aer/src/open_pulse/zspmv.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/density_matrix/densitymatrix.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/density_matrix/densitymatrix_state.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/density_matrix/densitymatrix_thrust.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/extended_stabilizer/ch_runner.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/extended_stabilizer/chlib/chstabilizer.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/extended_stabilizer/chlib/core.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/extended_stabilizer/gates.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/matrix_product_state.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/matrix_product_state_internal.cpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/matrix_product_state_internal.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/svd.cpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/matrix_product_state/svd.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/stabilizer/binary_vector.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/stabilizer/clifford.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/stabilizer/pauli.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/stabilizer/stabilizer_state.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/state.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/state_chunk.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/chunk.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/chunk_container.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/chunk_manager.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/cuStateVec_chunk_container.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/cuda_kernels.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/device_chunk_container.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/host_chunk_container.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/chunk/thrust_kernels.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/indexes.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/statevector/qubitvector.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/qubitvector_thrust.hpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/qv_avx2.cpp delete mode 100644 quantum/plugins/ibm/aer/src/simulators/statevector/qv_avx2.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/statevector/statevector_state.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/statevector/transformer.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/statevector/transformer_avx2.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/superoperator/superoperator.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/superoperator/superoperator_state.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/superoperator/superoperator_thrust.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/unitary/unitary_state.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/unitary/unitarymatrix.hpp delete mode 100755 quantum/plugins/ibm/aer/src/simulators/unitary/unitarymatrix_thrust.hpp delete mode 100644 quantum/plugins/ibm/aer/src/transpile/basic_opts.hpp delete mode 100644 quantum/plugins/ibm/aer/src/transpile/cacheblocking.hpp delete mode 100644 quantum/plugins/ibm/aer/src/transpile/circuitopt.hpp delete mode 100644 quantum/plugins/ibm/aer/src/transpile/fusion.hpp delete mode 100644 quantum/plugins/ibm/aer/tests/AerAcceleratorPulseTester.cpp delete mode 100644 quantum/plugins/ibm/aer/tests/AerNoiseModelTester.cpp delete mode 100644 quantum/plugins/ibm/new_aer/CMakeLists.txt delete mode 100644 quantum/plugins/ibm/new_aer/aer_accelerator.hpp delete mode 100644 quantum/plugins/ibm/new_aer/aer_noise_model.hpp delete mode 100644 quantum/plugins/ibm/new_aer/manifest.json delete mode 100644 quantum/plugins/ibm/new_aer/tests/CMakeLists.txt delete mode 100644 quantum/plugins/ibm/new_aer/tests/NewAerAcceleratorTester.cpp diff --git a/quantum/plugins/ibm/CMakeLists.txt b/quantum/plugins/ibm/CMakeLists.txt index 221e85606..1b9a72516 100644 --- a/quantum/plugins/ibm/CMakeLists.txt +++ b/quantum/plugins/ibm/CMakeLists.txt @@ -12,7 +12,7 @@ # *******************************************************************************/ add_subdirectory(aer) -add_subdirectory(new_aer) +#add_subdirectory(new_aer) set(LIBRARY_NAME xacc-ibm) diff --git a/quantum/plugins/ibm/aer/CMakeLists.txt b/quantum/plugins/ibm/aer/CMakeLists.txt index 9ed5cef96..840970a57 100644 --- a/quantum/plugins/ibm/aer/CMakeLists.txt +++ b/quantum/plugins/ibm/aer/CMakeLists.txt @@ -1,17 +1,19 @@ set(LIBRARY_NAME xacc-aer) if(NOT QIREE_MINIMAL_BUILD) -add_subdirectory(py-aer) +#add_subdirectory(py-aer) endif() +set(AER_SOURCE_DIR ${CMAKE_SOURCE_DIR}/tpls/qiskit-aer) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") if (NOT CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") - set(AER_SIMD_SOURCE_FILE src/simulators/statevector/qv_avx2.cpp) + set(AER_SIMD_SOURCE_FILE ${AER_SOURCE_DIR}/src/simulators/statevector/qv_avx2.cpp) endif() endif() file(GLOB SRC - accelerator/aer_accelerator.cpp + aer_accelerator.cpp ${AER_SIMD_SOURCE_FILE}) usfunctiongetresourcesource(TARGET ${LIBRARY_NAME} OUT SRC) @@ -19,23 +21,20 @@ usfunctiongeneratebundleinit(TARGET ${LIBRARY_NAME} OUT SRC) add_library(${LIBRARY_NAME} SHARED ${SRC}) +find_package(Python COMPONENTS Interpreter Development) + target_include_directories(${LIBRARY_NAME} PUBLIC . - accelerator - src - ../common - ${CMAKE_SOURCE_DIR}/tpls) + ${AER_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/tpls + ${CMAKE_SOURCE_DIR}/tpls/pybind11/include + ${Python_INCLUDE_DIRS}) + target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate + Python::Python ) - -if(NOT QIREE_MINIMAL_BUILD) - target_link_libraries(${LIBRARY_NAME} - PUBLIC xacc-py-aer-adapter - ) -endif(NOT QIREE_MINIMAL_BUILD) - if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") if(APPLE OR UNIX) @@ -51,7 +50,7 @@ if(OpenMP_CXX_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() -set(_bundle_name xacc_aer) +set(_bundle_name xacc_new_aer) set_target_properties(${LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_name} diff --git a/quantum/plugins/ibm/aer/accelerator/aer_accelerator.cpp b/quantum/plugins/ibm/aer/accelerator/aer_accelerator.cpp deleted file mode 100644 index 257b17619..000000000 --- a/quantum/plugins/ibm/aer/accelerator/aer_accelerator.cpp +++ /dev/null @@ -1,1075 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 UT-Battelle, LLC. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompanies this - * distribution. The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution - *License is available at https://eclipse.org/org/documents/edl-v10.php - * - * Contributors: - * Thien Nguyen - initial API and implementation - *******************************************************************************/ -#include "aer_accelerator.hpp" -#include "Accelerator.hpp" -#include "Utils.hpp" -#include "aer_noise_model.hpp" -#include "CommonGates.hpp" -#include "CountGatesOfTypeVisitor.hpp" -#include "InstructionIterator.hpp" - -#include "controllers/aer_controller.hpp" -#include "controllers/controller_execute.hpp" -#include "noise/readout_error.hpp" - -#include "cppmicroservices/BundleActivator.h" -#include "cppmicroservices/BundleContext.h" -#include "cppmicroservices/ServiceProperties.h" -#include "simulators/density_matrix/densitymatrix.hpp" -#include "xacc.hpp" -#include "xacc_service.hpp" - -#include -#include -#include "QObjGenerator.hpp" -#include "py-aer/aer_python_adapter.hpp" - -namespace xacc { -namespace quantum { - -#define IS_INTEGRAL(T) \ - typename std::enable_if::value>::type * = 0 - -template -std::string integral_to_binary_string(T byte, IS_INTEGRAL(T)) { - std::bitset bs(byte); - return bs.to_string(); -} -std::string hex_string_to_binary_string(const std::string &hex) { - auto hex_char_to_bin = [](char c) -> std::string { - switch (toupper(c)) { - case '0': - return "0000"; - case '1': - return "0001"; - case '2': - return "0010"; - case '3': - return "0011"; - case '4': - return "0100"; - case '5': - return "0101"; - case '6': - return "0110"; - case '7': - return "0111"; - case '8': - return "1000"; - case '9': - return "1001"; - case 'A': - return "1010"; - case 'B': - return "1011"; - case 'C': - return "1100"; - case 'D': - return "1101"; - case 'E': - return "1110"; - case 'F': - return "1111"; - } - throw std::runtime_error("Invalid Hex character!"); - return ""; - }; - - // start with '0x' - assert(hex.substr(0, 2) == "0x"); - std::string bin; - for (int i = 2; i != hex.length(); ++i) { - bin += hex_char_to_bin(hex[i]); - } - - return bin; -} - -HeterogeneousMap AerAccelerator::getProperties() { - auto props = physical_backend_properties; - // Insert 'shots' data - if (m_simtype == "qasm") { - props.insert("shots", m_shots); - } - return props; -} - -void AerAccelerator::initialize(const HeterogeneousMap ¶ms) { - - m_options = params; - noise_model.clear(); - m_simtype = "qasm"; - connectivity.clear(); - if (params.stringExists("qobj-compiler") && - (xacc::hasService(params.getString("qobj-compiler")) || - xacc::hasContributedService( - params.getString("qobj-compiler")))) { - xacc_to_qobj = xacc::getCompiler(params.getString("qobj-compiler")); - } else { - xacc_to_qobj = xacc::getCompiler("qobj"); - } - if (params.keyExists("shots")) { - m_shots = params.get("shots"); - } - - if (params.keyExists("seed")) { - m_seed = params.get("seed"); - } - if (params.stringExists("sim-type")) { - if (!xacc::container::contains( - std::vector{"qasm", "statevector", "pulse", - "density_matrix", "matrix_product_state"}, - params.getString("sim-type"))) { - xacc::warning("[Aer] warning, invalid sim-type (" + - params.getString("sim-type") + - "), must be qasm or statevector or density_matrix or " - "matrix_product_state."); - } else { - m_simtype = params.getString("sim-type"); - } - } - - // A custom sim method is specified with 'shots'; - // use qasm sim but set the method in QObj to force the method. - // e.g., statevector and density_matrix will not do shots, just returns the - // 'state'. - if (m_simtype != "qasm" && params.keyExists("shots")) { - m_simtype = "qasm"; - } - - if (params.stringExists("backend")) { - auto ibm_noise_model = xacc::getService("IBM"); - ibm_noise_model->initialize(params); - auto json_str = ibm_noise_model->toJson(); - noise_model = nlohmann::json::parse(json_str); - auto ibm = xacc::getAccelerator("ibm:" + params.getString("backend")); - physical_backend_properties = ibm->getProperties(); - if (m_simtype == "pulse") { - // If pulse mode, must contribute pulse cmd-def. - ibm->contributeInstructions(); - } - // Set connectivity based on the backend: - connectivity = ibm->getConnectivity(); - } else if (params.stringExists("noise-model")) { - std::string noise_model_str = params.getString("noise-model"); - // Check if this is a file name - std::ifstream test(noise_model_str); - if (test) { - std::string str((std::istreambuf_iterator(test)), - std::istreambuf_iterator()); - noise_model = nlohmann::json::parse(str); - } else { - noise_model = nlohmann::json::parse(params.getString("noise-model")); - } - - // need this for ro error decorator - std::vector p01s, p10s; - auto errors = noise_model["errors"]; - for (auto error : errors) { - if (error["operations"].get>() == - std::vector{"measure"}) { - auto probs = - error["probabilities"].get>>(); - auto meas1prep0 = probs[0][1]; - auto meas0prep1 = probs[1][0]; - p01s.push_back(meas0prep1); - p10s.push_back(meas1prep0); - } - } - physical_backend_properties.insert("p01s", p01s); - physical_backend_properties.insert("p10s", p10s); - - } - AER::Hacks::maybe_load_openmp(""); - initialized = true; -} -double AerAccelerator::calcExpectationValueZ( - const std::vector> &in_stateVec, - const std::vector &in_bits) { - const auto hasEvenParity = - [](size_t x, const std::vector &in_qubitIndices) -> bool { - size_t count = 0; - for (const auto &bitIdx : in_qubitIndices) { - if (x & (1ULL << bitIdx)) { - count++; - } - } - return (count % 2) == 0; - }; - - double result = 0.0; - for (uint64_t i = 0; i < in_stateVec.size(); ++i) { - result += (hasEvenParity(i, in_bits) ? 1.0 : -1.0) * - std::norm(std::complex(in_stateVec[i].first, - in_stateVec[i].second)); - } - - return result; -} - -double AerAccelerator::calcExpectationValueZFromDensityMatrix( - const std::vector>> &in_densityMat, - const std::vector &in_bits) { - const auto hasEvenParity = - [](size_t x, const std::vector &in_qubitIndices) -> bool { - size_t count = 0; - for (const auto &bitIdx : in_qubitIndices) { - if (x & (1ULL << bitIdx)) { - count++; - } - } - return (count % 2) == 0; - }; - - double result = 0.0; - for (uint64_t i = 0; i < in_densityMat.size(); ++i) { - const auto &diag_elem = in_densityMat[i][i]; - // The diag. elements of the DM should be real. - assert(std::abs(diag_elem.second) < 1e-3); - // When using DM elements, don't need the square-norm. - result += ((hasEvenParity(i, in_bits) ? 1.0 : -1.0) * diag_elem.first); - } - - return result; -} - -void AerAccelerator::execute( - std::shared_ptr buffer, - const std::shared_ptr program) { - if (m_simtype == "qasm") { - auto qobj_str = xacc_to_qobj->translate(program); - - nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"]; - j["config"]["shots"] = m_shots; - j["config"]["noise_model"] = noise_model; - // If a seed was set: - if (m_seed > 0) { - j["config"]["seed_simulator"] = m_seed; - } - - if (m_options.stringExists("sim-type")) { - const std::string requestedMethod = m_options.getString("sim-type"); - if (requestedMethod == "statevector") { - j["config"]["method"] = "statevector"; - } else if (requestedMethod == "density_matrix") { - j["config"]["method"] = "density_matrix"; - } else if (requestedMethod == "matrix_product_state") { - j["config"]["method"] = "matrix_product_state"; - } else { - j["config"]["method"] = "automatic"; - } - } - - // xacc::set_verbose(true); - // xacc::info("Shots Qobj:\n" + j.dump(2)); - // Initialize QOBJ - AER::Qobj qobj(j); - AER::Controller controller; - // Set config - controller.set_config(qobj.config); - assert(qobj.circuits.size() == 1); - - if (m_options.keyExists>>( - "initial_state")) { - const std::vector> intial_state = - m_options.get>>("initial_state"); - if (intial_state.size() != (1ULL << buffer->size())) { - xacc::error("Dimension mismatch in 'initial_state', expected size of " + - std::to_string(1ULL << buffer->size())); - } - const double norm = std::accumulate( - intial_state.begin(), intial_state.end(), 0.0, - [](double current_norm, const std::complex &val) { - return current_norm + std::norm(val); - }); - if (std::abs(norm - 1.0) > 1e-12) { - xacc::error("Initial state vector input is not normalized."); - } - // Add initialize op to set the initial input state - AER::Operations::Op op; - op.type = AER::Operations::OpType::initialize; - op.name = "initialize"; - for (int q = 0; q < buffer->size(); ++q) { - op.qubits.emplace_back(q); - } - op.params = intial_state; - qobj.circuits[0].ops.insert(qobj.circuits[0].ops.begin(), op); - qobj.circuits[0].set_params(false); - } - - // Run qobj circuits - auto result = controller.execute(qobj.circuits, qobj.noise_model, qobj.config); - if (result.status != AER::Result::Status::completed) { - xacc::error("Failed to complete the simulation! Error: " + - result.message); - } - assert(result.results.size() == 1); - auto results = result.results.front(); - auto counts = - results.data.to_json()["counts"].get>(); - // Process bitStr to be an n-Measure string in msb - CountGatesOfTypeVisitor cc(program); - const int nMeasures = cc.countGates(); - for (auto &kv : counts) { - std::string hexStr = kv.first; - int nOccurrences = kv.second; - auto bitStr = hex_string_to_binary_string(hexStr); - std::string actual(nMeasures, '0'); - for (int i = 0; i < nMeasures; i++) { - if (bitStr.length() > i) { - actual[actual.length() - 1 - i] = bitStr[bitStr.length() - i - 1]; - } - } - buffer->appendMeasurement(actual, nOccurrences); - } - } else if (m_simtype == "pulse") { - // Get the correct QObject Generator - auto qobjGen = xacc::getService("pulse"); - auto chosenBackend = nlohmann::json::parse(physical_backend_properties.getString("config-json")); - // Unused - const std::string getBackendPropsResponse = "{}"; - auto defaults_response = nlohmann::json::parse(physical_backend_properties.getString("defaults-json")); - auto ibmPulseAssembler = xacc::getService("ibm-pulse"); - auto kernel = xacc::ir::asComposite(program->clone()); - - // Remove measures, add measure all (at the end) - kernel->clear(); - InstructionIterator iter(program); - std::vector measured_bits; - while (iter.hasNext()) { - auto next = iter.next(); - if (!next->isComposite() && next->name() != "Measure") { - kernel->addInstruction(next); - } else if (next->name() == "Measure") { - measured_bits.push_back(next->bits()[0]); - } - } - - auto provider = xacc::getIRProvider("quantum"); - for (size_t qId = 0; qId < buffer->size(); ++qId) { - kernel->addInstruction(provider->createInstruction("Measure", qId)); - } - - // Assemble pulse composite from the input kernel. - ibmPulseAssembler->apply(kernel, nullptr); - // Generate the QObject JSON - auto qobjJsonStr = qobjGen->getQObjJsonStr({kernel}, m_shots, chosenBackend, - getBackendPropsResponse, - connectivity, defaults_response); - xacc::info("Qobj:\n" + qobjJsonStr); - auto hamiltonianJson = chosenBackend["hamiltonian"]; - // Remove unrelated fields (could contain problematic characters) - hamiltonianJson.erase("description"); - hamiltonianJson.erase("h_latex"); - xacc::info("Hamiltonian Json:\n" + hamiltonianJson.dump()); - const auto dt = chosenBackend["dt"].get(); - const auto qubitFreqEst = defaults_response["qubit_freq_est"].get>(); - const auto uLoFreqs = chosenBackend["u_channel_lo"]; - std::vector uLoRefs; - for (auto loIter = uLoFreqs.begin(); loIter != uLoFreqs.end(); ++loIter) { - auto uLoConfig = *((*loIter).begin()); - uLoRefs.emplace_back(uLoConfig["q"].get()); - } - // Run the simulation via Python - const std::string resultJson = - xacc::aer::runPulseSim(hamiltonianJson.dump(), dt, qubitFreqEst, uLoRefs, qobjJsonStr); - auto result_json = nlohmann::json::parse(resultJson); - auto count_json = result_json["counts"].get>(); - for (const auto &[hexStr, nOccurrences] : count_json) { - auto bitStr = hex_string_to_binary_string(hexStr); - // Process bitStr to be an n-Measure string in msb - std::string actual = ""; - const auto nMeasures = measured_bits.size(); - for (int i = 0; i < nMeasures; i++) { - actual += "0"; - } - - for (int i = 0; i < nMeasures; i++) { - actual[actual.length() - 1 - i] = bitStr[bitStr.length() - measured_bits[i] - 1]; - } - - buffer->appendMeasurement(actual, nOccurrences); - } - - auto state_vector = result_json["statevector"].get>>(); - buffer->addExtraInfo("state", state_vector); - } else if (m_simtype == "density_matrix") { - // remove all measures, don't need them - auto tmp = xacc::ir::asComposite(program->clone()); - tmp->clear(); - AER::reg_t measured_bits; - InstructionIterator iter(program); - while (iter.hasNext()) { - auto next = iter.next(); - if (!next->isComposite() && next->name() != "Measure") { - tmp->addInstruction(next); - } else if (next->name() == "Measure") { - measured_bits.push_back(next->bits()[0]); - } - } - // In "density_matrix" simulation mode, always include Id gates - // if they are explicitly added to the Composite. - auto qobj_str = xacc_to_qobj->translate(tmp, {{"skip-id-gates", false}}); - nlohmann::json qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; - qObjJson["config"]["method"] = "density_matrix"; - qObjJson["config"]["enable_truncation"] = false; - qObjJson["config"]["noise_model"] = noise_model; - AER::DensityMatrix::State> densityMat; - AER::RngEngine rng; - AER::Qobj qobj(qObjJson); - // std::cout << "QObj:\n" << qobj_str << "\n"; - assert(qobj.circuits.size() == 1); - auto circ = qobj.circuits[0]; - // Output data container - AER::ExperimentResult data; - densityMat.initialize_creg(circ.num_memory, circ.num_registers); - densityMat.initialize_qreg(buffer->size()); - if (m_options.keyExists>>( - "initial_state")) { - const std::vector> intial_state = - m_options.get>>("initial_state"); - if (intial_state.size() != (1ULL << buffer->size())) { - xacc::error("Dimension mismatch in 'initial_state', expected size of " + - std::to_string(1ULL << buffer->size())); - } - const double norm = std::accumulate( - intial_state.begin(), intial_state.end(), 0.0, - [](double current_norm, const std::complex &val) { - return current_norm + std::norm(val); - }); - if (std::abs(norm - 1.0) > 1e-12) { - xacc::error("Initial state vector input is not normalized."); - } - densityMat.qreg().initialize_from_vector(intial_state); - } - // std::cout << "Num op: " << circ.ops.size() << "\n"; - if (!noise_model.empty()) { - auto noise = qobj.noise_model; - noise.enable_superop_method(); - auto opt_circ = noise.sample_noise( - circ, rng, AER::Noise::NoiseModel::Method::superop); - densityMat.apply_ops(opt_circ.ops.begin(), opt_circ.ops.end(), data, rng); - } else { - densityMat.apply_ops(circ.ops.begin(), circ.ops.end(), data, rng); - } - // std::cout << "Result: \n" << data.to_json().dump() << "\n"; - const double exp_val = densityMat.qreg().expval_pauli( - measured_bits, std::string(measured_bits.size(), 'Z')); - - auto dmData = densityMat.move_to_matrix(0); - const auto length = dmData.size(); - assert(length == (1ULL << buffer->size()) * (1ULL << buffer->size())); - std::complex *dmPtr = dmData.move_to_buffer(); - std::vector> flattenDm; - flattenDm.reserve(length); - for (int i = 0; i < length; ++i) { - flattenDm.emplace_back(dmPtr[i].real(), dmPtr[i].imag()); - } - buffer->addExtraInfo("density_matrix", flattenDm); - - ExecutionInfo::DensityMatrixType dm(1ULL << buffer->size()); - auto *startAddr = dmPtr; - for (auto &row : dm) { - auto *endAddr = startAddr + (1ULL << buffer->size()); - row.assign(startAddr, endAddr); - startAddr = endAddr; - } - m_executionInfo = { - {ExecutionInfo::DmKey, - std::make_shared(std::move(dm))}}; - buffer->addExtraInfo("exp-val-z", exp_val); - } - else { - assert(m_simtype == "statevector"); - // statevector - // remove all measures, don't need them - auto tmp = xacc::ir::asComposite(program->clone()); - tmp->clear(); - AER::reg_t measured_bits; - InstructionIterator iter(program); - while (iter.hasNext()) { - auto next = iter.next(); - if (!next->isComposite() && next->name() != "Measure") { - tmp->addInstruction(next); - } else if (next->name() == "Measure") { - measured_bits.push_back(next->bits()[0]); - } - } - auto qobj_str = xacc_to_qobj->translate(tmp); - nlohmann::json qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; - qObjJson["config"]["method"] = "statevector"; - qObjJson["config"]["enable_truncation"] = false; - AER::Statevector::State> stateVec; - AER::RngEngine rng; - AER::Qobj qobj(qObjJson); - // std::cout << "QObj:\n" << qobj_str << "\n"; - assert(qobj.circuits.size() == 1); - auto circ = qobj.circuits[0]; - // Output data container - AER::ExperimentResult data; - stateVec.initialize_creg(circ.num_memory, circ.num_registers); - stateVec.initialize_qreg(buffer->size()); - if (m_options.keyExists>>( - "initial_state")) { - const std::vector> intial_state = - m_options.get>>("initial_state"); - if (intial_state.size() != (1ULL << buffer->size())) { - xacc::error("Dimension mismatch in 'initial_state', expected size of " + - std::to_string(1ULL << buffer->size())); - } - const double norm = std::accumulate( - intial_state.begin(), intial_state.end(), 0.0, - [](double current_norm, const std::complex &val) { - return current_norm + std::norm(val); - }); - if (std::abs(norm - 1.0) > 1e-12) { - xacc::error("Initial state vector input is not normalized."); - } - stateVec.qreg().initialize_from_vector(intial_state); - } - // std::cout << "Num op: " << circ.ops.size() << "\n"; - stateVec.apply_ops(circ.ops.begin(), circ.ops.end(), data, rng); - // std::cout << "Result: \n" << data.to_json().dump() << "\n"; - const double exp_val = stateVec.qreg().expval_pauli( - measured_bits, std::string(measured_bits.size(), 'Z')); - - auto stateVecData = stateVec.move_to_vector(0); - const auto length = stateVecData.size(); - std::complex *statePtr = stateVecData.move_to_buffer(); - ExecutionInfo::WaveFuncType wavefn(statePtr, statePtr + length); - // std::cout << "HOWDY: " << wavefn.size() << "\n"; - // for (int i = 0; i < wavefn.size(); ++i) { - // std::cout << wavefn[i] << "\n"; - // } - buffer->addExtraInfo("exp-val-z", exp_val); - m_executionInfo = { - {ExecutionInfo::WaveFuncKey, - std::make_shared(std::move(wavefn))}}; - } -} - -void AerAccelerator::execute( - std::shared_ptr buffer, - const std::vector> - compositeInstructions) { - for (auto &f : compositeInstructions) { - auto tmpBuffer = - std::make_shared(f->name(), buffer->size()); - execute(tmpBuffer, f); - buffer->appendChild(f->name(), tmpBuffer); - } -} - -void AerAccelerator::apply(std::shared_ptr buffer, - std::shared_ptr inst) { - static AER::Statevector::State> stateVec; - static auto provider = xacc::getIRProvider("quantum"); - static AER::RngEngine rng; - static std::set knownBuffers; - if (!xacc::container::contains(knownBuffers, buffer.get())) { - stateVec.initialize_qreg(buffer->size()); - knownBuffers.emplace(buffer.get()); - } - if (inst->isComposite() || inst->isAnalog()) { - xacc::error("Only gates are allowed."); - } - xacc::info("Apply: " + inst->toString()); - if (inst->name() != "Measure") { - auto tempComp = provider->createComposite("tmp"); - tempComp->addInstruction(inst); - auto qobj_str = xacc_to_qobj->translate(tempComp); - auto qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; - qObjJson["config"]["enable_truncation"] = false; - AER::Qobj qobj(qObjJson); - // std::cout << "QObj:\n" << qobj_str << "\n"; - assert(qobj.circuits.size() == 1); - auto circ = qobj.circuits[0]; - // Output data container - AER::ExperimentResult data; - // std::cout << "Num op: " << circ.ops.size() << "\n"; - stateVec.apply_ops(circ.ops.begin(), circ.ops.end(), data, rng); - // std::cout << "Result: \n" << data.to_json().dump() << "\n"; - // auto wavefn = stateVec.copy_to_vector(0); - // std::cout << "HOWDY: " << wavefn.size() << "\n"; - // for (int i = 0; i < wavefn.size(); ++i) { - // std::cout << wavefn[i] << "\n"; - // } - } - // stateVec.add_creg_to_data(data); - // If it was a Measure op: - else { - AER::reg_t measured_bits{inst->bits()[0]}; - const auto probs = stateVec.qreg().probabilities(measured_bits); - assert(probs.size() == 2); - assert(std::abs(1.0 - probs[0] - probs[1]) < 1e-12); - // Randomly pick outcome and return pair - auto outcome = rng.rand_int(probs); - // std::cout << "Outcome: " << outcome << "\n"; - assert(outcome == 0 || outcome == 1); - // std::cout << "Probs: " << probs[0] << " " << probs[1] << "\n"; - std::vector> mdiag(2, 0.); - mdiag[outcome] = 1. / std::sqrt(probs[outcome]); - stateVec.qreg().apply_diagonal_matrix(measured_bits, mdiag); - buffer->measure(inst->bits()[0], outcome); - } -} - -void IbmqNoiseModel::initialize(const HeterogeneousMap ¶ms) { - m_nbQubits = 0; - m_qubitT1.clear(); - m_qubitT2.clear(); - m_gateErrors.clear(); - m_gateDurations.clear(); - m_roErrors.clear(); - m_connectivity.clear(); - // Note: we support both remote backend JSON and cache JSON string. - // So that we can test this with offline JSON. - if (params.stringExists("backend") || params.stringExists("backend-json")) { - const auto backendJsonStr = [&]() { - if (params.stringExists("backend")) { - auto ibm = xacc::getAccelerator("ibm:" + params.getString("backend")); - auto props = ibm->getProperties().get("total-json"); - m_connectivity = ibm->getConnectivity(); - return props; - } - return params.getString("backend-json"); - }(); - - auto backEndJson = nlohmann::json::parse(backendJsonStr); - // Cache the backend properties JSON. - m_backendPropertiesJson = backendJsonStr; - // Parse qubit data: - auto qubitsData = backEndJson["qubits"]; - size_t nbQubit = 0; - for (auto qubitIter = qubitsData.begin(); qubitIter != qubitsData.end(); - ++qubitIter) { - std::optional meas0Prep1, meas1Prep0; - // Each qubit contains an array of properties. - for (auto probIter = qubitIter->begin(); probIter != qubitIter->end(); - ++probIter) { - const auto probObj = *probIter; - const std::string probName = probObj["name"].get(); - const double probVal = probObj["value"].get(); - const std::string unit = probObj["unit"].get(); - if (probName == "T1") { - assert(unit == "µs" || unit == "us" || unit == "ns"); - m_qubitT1.emplace_back( - (unit == "µs" || unit == "us") ? 1000.0 * probVal : probVal); - } - - if (probName == "T2") { - assert(unit == "µs" || unit == "us" || unit == "ns"); - m_qubitT2.emplace_back( - (unit == "µs" || unit == "us") ? 1000.0 * probVal : probVal); - } - - if (probName == "prob_meas0_prep1") { - assert(unit.empty()); - meas0Prep1 = probVal; - } - - if (probName == "prob_meas1_prep0") { - assert(unit.empty()); - meas1Prep0 = probVal; - } - } - assert(meas0Prep1.has_value() && meas1Prep0.has_value()); - m_roErrors.emplace_back(std::make_pair(*meas0Prep1, *meas1Prep0)); - - nbQubit++; - } - m_nbQubits = nbQubit; - assert(m_qubitT1.size() == m_nbQubits); - assert(m_qubitT2.size() == m_nbQubits); - assert(m_roErrors.size() == m_nbQubits); - - // Parse gate data: - auto gateData = backEndJson["gates"]; - for (auto gateIter = gateData.begin(); gateIter != gateData.end(); - ++gateIter) { - auto gateObj = *gateIter; - const std::string gateName = gateObj["name"].get(); - auto gateParams = gateObj["parameters"]; - for (auto it = gateParams.begin(); it != gateParams.end(); ++it) { - auto paramObj = *it; - const std::string paramName = paramObj["name"].get(); - if (paramName == "gate_length") { - const std::string unit = paramObj["unit"].get(); - assert(unit == "µs" || unit == "us" || unit == "ns"); - const double gateLength = - (unit == "µs" || unit == "us") - ? 1000.0 * paramObj["value"].get() - : paramObj["value"].get(); - const bool insertOk = - m_gateDurations.insert({gateName, gateLength}).second; - if (gateName.rfind("sx", 0) == 0) { - // This device properties were specified in the { rz, sx, cx } basis. - // We add equivalent data for { u1, u2, u3 } basis set as well. - // For every sx gate, add equiv. data for u1, u2, u3 gates. - // Note: some of our noisy simulators don't split a gate into multiple sx gates, - // hence, they cannot simulate noise at that level. - const std::string qubitOperandSuffix = gateName.substr(2); - const std::string u1GateName = "u1" + qubitOperandSuffix; - const std::string u2GateName = "u2" + qubitOperandSuffix; - const std::string u3GateName = "u3" + qubitOperandSuffix; - m_gateDurations.insert({u1GateName, 0.0}); - m_gateDurations.insert({u2GateName, gateLength}); - m_gateDurations.insert({u3GateName, 2.0 * gateLength}); - } - // Must not contain duplicates. - assert(insertOk); - } - - if (paramName == "gate_error") { - assert(paramObj["unit"].get().empty()); - const bool insertOk = - m_gateErrors.insert({gateName, paramObj["value"].get()}) - .second; - // Must not contain duplicates. - assert(insertOk); - if (gateName.rfind("sx", 0) == 0) { - const std::string qubitOperandSuffix = gateName.substr(2); - const std::string u1GateName = "u1" + qubitOperandSuffix; - const std::string u2GateName = "u2" + qubitOperandSuffix; - const std::string u3GateName = "u3" + qubitOperandSuffix; - m_gateErrors.insert({u1GateName, 0.0}); - m_gateErrors.insert({u2GateName, paramObj["value"].get()}); - m_gateErrors.insert({u3GateName, 2.0 * paramObj["value"].get()}); - } - } - } - } - } -} - -std::string -IbmqNoiseModel::getUniversalGateEquiv(xacc::quantum::Gate &in_gate) const { - if (in_gate.bits().size() == 1 && in_gate.name() != "Measure") { - // Note: rotation around Z is a noiseless *u1* operation; - // *u2* operations are those that requires a half-length rotation; - // *u3* operations are those that requires a full-length rotation. - static const std::unordered_map - SINGLE_QUBIT_GATE_MAP{{"X", "u3"}, {"Y", "u3"}, {"Z", "u1"}, - {"H", "u2"}, {"U", "u3"}, {"T", "u1"}, - {"Tdg", "u1"}, {"S", "u1"}, {"Sdg", "u1"}, - {"Rz", "u1"}, {"Rx", "u3"}, {"Ry", "u3"}}; - const auto iter = SINGLE_QUBIT_GATE_MAP.find(in_gate.name()); - // If cannot find the gate, just treat that as a noiseless u1 op. - const std::string universalGateName = - (iter == SINGLE_QUBIT_GATE_MAP.end()) ? "u1" : iter->second; - return universalGateName + std::to_string(in_gate.bits()[0]); - } - - if (in_gate.bits().size() == 2) { - return "cx" + std::to_string(in_gate.bits()[0]) + "_" + - std::to_string(in_gate.bits()[1]); - } - - return "id" + std::to_string(in_gate.bits()[0]); -} - -// Return gate time, T1, T2 -std::tuple -IbmqNoiseModel::relaxationParams(xacc::quantum::Gate &in_gate, - size_t in_qubitIdx) const { - const std::string universalGateName = getUniversalGateEquiv(in_gate); - const auto gateDurationIter = m_gateDurations.find(universalGateName); - assert(gateDurationIter != m_gateDurations.end()); - const double gateDuration = gateDurationIter->second; - const double qubitT1 = m_qubitT1[in_qubitIdx]; - const double qubitT2 = m_qubitT2[in_qubitIdx]; - return std::make_tuple(gateDuration, qubitT1, qubitT2); -} - -std::vector>> -IbmqNoiseModel::thermalRelaxationChoiMat(double in_gateTime, double in_T1, - double in_T2) const { - const double rate1 = 1.0 / in_T1; - const double pReset = 1.0 - std::exp(-in_gateTime * rate1); - - const double rate2 = 1.0 / in_T2; - const double expT2 = std::exp(-in_gateTime * rate2); - const double p0 = 1.0; - const double p1 = 0.0; - return {{1 - p1 * pReset, 0, 0, expT2}, - {0, p1 * pReset, 0, 0}, - {0, 0, p0 * pReset, 0}, - {expT2, 0, 0, 1 - p0 * pReset}}; -} - -std::vector IbmqNoiseModel::calculateDepolarizing( - xacc::quantum::Gate &in_gate, - const std::vector>> &in_relaxationError) - const { - // Compute the depolarizing channel error parameter in the - // presence of T1/T2 thermal relaxation. - // Hence we have that the depolarizing error probability - // for the composed depolarization channel is - // p = dim * (F(E_relax) - F) / (dim * F(E_relax) - 1) - const double averageThermalError = - 1.0 - averageGateFidelity(in_gate, in_relaxationError); - const std::string universalGateName = getUniversalGateEquiv(in_gate); - // Retrieve the error rate: - const auto gateErrorIter = m_gateErrors.find(universalGateName); - const double gateError = - (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; - // If the backend gate error (estimated by randomized benchmarking) is more - // than thermal relaxation error. We need to add depolarization to simulate - // the total gate error. - if (gateError > averageThermalError) { - // Model gate error entirely as depolarizing error - const double depolError = 2 * (gateError - averageThermalError) / - (2 * (1 - averageThermalError) - 1); - return {depolError}; - } - return {0.0}; -} - -double IbmqNoiseModel::averageGateFidelity( - xacc::quantum::Gate &in_gate, - const std::vector>> &in_relaxationError) - const { - // We only handle single-qubit gates for now. - if (in_gate.bits().size() == 1 && in_relaxationError.size() == 4) { - // Note: this is based on the simplified amplitude-damping channel - const double processFidelity = - (in_relaxationError[0][0].real() + in_relaxationError[0][3].real() + - in_relaxationError[3][0].real() + in_relaxationError[3][3].real()) / - 4.0; - - assert(processFidelity <= 1.0); - const double averageFidelity = (4.0 * processFidelity + 1.0) / 5.0; - return averageFidelity; - } - return 1.0; -} - -double IbmqNoiseModel::gateErrorProb(xacc::quantum::Gate &gate) const { - const auto universalGateName = getUniversalGateEquiv(gate); - const auto gateErrorIter = m_gateErrors.find(universalGateName); - return (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; -} - -std::vector -IbmqNoiseModel::getNoiseChannels(xacc::quantum::Gate &gate) const { - std::vector krausOps; - const auto noiseUtils = xacc::getService("default"); - if (gate.bits().size() == 1 && gate.name() != "Measure") { - // Amplitude damping + dephasing - const auto [gateDuration, qubitT1, qubitT2] = - relaxationParams(gate, gate.bits()[0]); - const auto relaxationError = - thermalRelaxationChoiMat(gateDuration, qubitT1, qubitT2); - - // Depolarization - const auto dpAmpl = calculateDepolarizing(gate, relaxationError); - if (!dpAmpl.empty()) { - const double probDP = dpAmpl[0]; - const std::vector>> depolErrorChoi{ - {1.0 - probDP / 2.0, 0., 0., 1.0 - probDP}, - {0., probDP / 2.0, 0., 0.}, - {0., 0., probDP / 2.0, 0.}, - {1.0 - probDP, 0., 0., 1.0 - probDP / 2.0}}; - const auto noiseUtils = xacc::getService("default"); - krausOps.emplace_back(NoiseChannelKraus(gate.bits(), noiseUtils->choiToKraus(depolErrorChoi), KrausMatBitOrder::MSB)); - } - } - // For two-qubit gates, we currently only support - // amplitude damping on both qubits (scaled by gate time). - // We don't have ability to handle multi-qubit depolarization - // in TNQVM yet. - if (gate.bits().size() == 2) { - - for (const auto &qubitIdx : gate.bits()) { - const auto [gateDuration, qubitT1, qubitT2] = - relaxationParams(gate, qubitIdx); - const auto relaxationError = - thermalRelaxationChoiMat(gateDuration, qubitT1, qubitT2); - krausOps.emplace_back(NoiseChannelKraus({qubitIdx}, noiseUtils->choiToKraus(relaxationError), KrausMatBitOrder::MSB)); - } - } - return krausOps; -} - -std::string IbmqNoiseModel::toJson() const { - // First, check if Qiskit is available, - // try to use Qiskit util if possible. - const std::string noiseModelJson = - xacc::aer::noiseModelFromBackendProperties(m_backendPropertiesJson); - if (!noiseModelJson.empty()) { - xacc::info("Qiskit generated noise model:\n" + noiseModelJson); - return noiseModelJson; - } - - // No Qiskit, create the noise model by ourselves from the backend properties. - // Aer noise model Json - nlohmann::json noiseModel; - std::vector noiseElements; - // Adds RO errors: - const auto roErrors = readoutErrors(); - for (size_t qIdx = 0; qIdx < roErrors.size(); ++qIdx) { - const auto &[meas0Prep1, meas1Prep0] = roErrors[qIdx]; - const std::vector> probs{{1 - meas1Prep0, meas1Prep0}, - {meas0Prep1, 1 - meas0Prep1}}; - nlohmann::json element; - element["type"] = "roerror"; - element["operations"] = std::vector{"measure"}; - element["probabilities"] = probs; - element["gate_qubits"] = std::vector>{{qIdx}}; - noiseElements.push_back(element); - } - - const auto noiseUtils = xacc::getService("default"); - // Add Kraus noise: - // (1) Single-qubit gate noise: - // Note: we must add noise ops for u2, u3, and cx gates: - for (size_t qIdx = 0; qIdx < roErrors.size(); ++qIdx) { - // For mapping purposes: - // U2 == Hadamard gate - // U3 == X gate - Hadamard gateU2(qIdx); - X gateU3(qIdx); - const std::unordered_map gateMap{ - {"u2", &gateU2}, {"u3", &gateU3}}; - - for (const auto &[gateName, gate] : gateMap) { - const auto errorChannels = getNoiseChannels(*gate); - nlohmann::json element; - element["type"] = "qerror"; - element["operations"] = std::vector{gateName}; - element["gate_qubits"] = std::vector>{{qIdx}}; - std::vector krausOps; - for (const auto &error : errorChannels) { - const auto krausOpMats = error.mats; - nlohmann::json instruction; - instruction["name"] = "kraus"; - instruction["qubits"] = std::vector{0}; - instruction["params"] = krausOpMats; - krausOps.emplace_back(instruction); - } - element["instructions"] = - std::vector>{krausOps}; - element["probabilities"] = std::vector{1.0}; - noiseElements.push_back(element); - } - } - - // (2) Two-qubit gate noise: - for (const auto &[qubit1, qubit2] : m_connectivity) { - // We need to add noise for both CNOT directions - // Note: the duration of them can be different, - // hence the noise channels. - CNOT cx1(std::vector{(size_t)qubit1, (size_t)qubit2}); - CNOT cx2(std::vector{(size_t)qubit2, (size_t)qubit1}); - const std::vector cxGates{&cx1, &cx2}; - for (const auto &cx : cxGates) { - const auto errorChannels = getNoiseChannels(*cx); - assert(errorChannels.size() == 2); - nlohmann::json element; - element["type"] = "qerror"; - element["operations"] = - std::vector{getUniversalGateEquiv(*cx)}; - element["gate_qubits"] = - std::vector>{cx->bits()}; - std::vector krausOps; - size_t noiseBitIdx = 0; - for (const auto &error : errorChannels) { - const auto krausOpMats = error.mats; - nlohmann::json instruction; - instruction["name"] = "kraus"; - instruction["qubits"] = std::vector{noiseBitIdx++}; - instruction["params"] = krausOpMats; - krausOps.emplace_back(instruction); - } - assert(krausOps.size() == 2); - element["instructions"] = - std::vector>{krausOps}; - element["probabilities"] = std::vector{1.0}; - noiseElements.push_back(element); - } - } - - noiseModel["errors"] = noiseElements; - return noiseModel.dump(6); -} - -std::vector IbmqNoiseModel::averageSingleQubitGateFidelity() const { - std::vector result; - // Use U3 gate fidelity: - for (size_t qId = 0; qId < m_nbQubits; ++qId) { - const std::string gateName = "u3_" + std::to_string(qId); - const auto gateErrorIter = m_gateErrors.find(gateName); - const double gateError = - (gateErrorIter == m_gateErrors.end()) ? 0.0 : gateErrorIter->second; - result.emplace_back(1.0 - gateError); - } - return result; -} - -std::vector> -IbmqNoiseModel::averageTwoQubitGateFidelity() const { - std::vector> result; - for (const auto &[gateName, gateError] : m_gateErrors) { - if (gateName.rfind("cx", 0) == 0) { - // CNOT gate: - const std::size_t pos = gateName.find("_"); - const std::string firstArg = gateName.substr(2, pos - 2); - const std::string secondArg = gateName.substr(pos + 1); - const auto firstBit = std::atoi(firstArg.c_str()); - const auto secondBit = std::atoi(secondArg.c_str()); - result.emplace_back( - std::make_tuple(firstBit, secondBit, 1.0 - gateError)); - } - } - - return result; -} - -std::string -AerAccelerator::getNativeCode(std::shared_ptr program, - const HeterogeneousMap &config) { - auto qobj_str = xacc_to_qobj->translate(program); - nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"]; - return j.dump(2); -} -} // namespace quantum -} // namespace xacc - -using namespace cppmicroservices; - -namespace { - -/** - */ -class US_ABI_LOCAL AerActivator : public BundleActivator { - -public: - AerActivator() {} - - /** - */ - void Start(BundleContext context) { - auto xt = std::make_shared(); - context.RegisterService(xt); - context.RegisterService( - std::make_shared()); - } - - /** - */ - void Stop(BundleContext /*context*/) {} -}; - -} // namespace - -CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(AerActivator) diff --git a/quantum/plugins/ibm/new_aer/aer_accelerator.cpp b/quantum/plugins/ibm/aer/aer_accelerator.cpp similarity index 97% rename from quantum/plugins/ibm/new_aer/aer_accelerator.cpp rename to quantum/plugins/ibm/aer/aer_accelerator.cpp index c56e51176..9871226f2 100644 --- a/quantum/plugins/ibm/new_aer/aer_accelerator.cpp +++ b/quantum/plugins/ibm/aer/aer_accelerator.cpp @@ -20,6 +20,7 @@ #include "controllers/aer_controller.hpp" #include "controllers/controller_execute.hpp" +#include "framework/circuit.hpp" #include "noise/readout_error.hpp" #include "cppmicroservices/BundleActivator.h" @@ -405,7 +406,7 @@ void AerAccelerator::execute( auto state_vector = result_json["statevector"].get>>(); buffer->addExtraInfo("state", state_vector); - } else if (m_simtype == "density_matrix") { + }*/ else if (m_simtype == "density_matrix") { // remove all measures, don't need them auto tmp = xacc::ir::asComposite(program->clone()); tmp->clear(); @@ -432,6 +433,7 @@ void AerAccelerator::execute( // std::cout << "QObj:\n" << qobj_str << "\n"; assert(qobj.circuits.size() == 1); auto circ = qobj.circuits[0]; + //std::shared_ptr circ = std::make_shared(qObjJson); // Output data container AER::ExperimentResult data; densityMat.initialize_creg(circ->num_memory, circ->num_registers); @@ -454,12 +456,13 @@ void AerAccelerator::execute( } densityMat.qreg().initialize_from_vector(intial_state); } + // std::cout << "Num op: " << circ.ops.size() << "\n"; if (!noise_model.empty()) { auto noise = qobj.noise_model; noise.enable_superop_method(); auto opt_circ = noise.sample_noise( - circ, rng, AER::Noise::NoiseModel::Method::superop); + *circ, rng, AER::Noise::NoiseModel::Method::superop); densityMat.apply_ops(opt_circ.ops.begin(), opt_circ.ops.end(), data, rng); } else { densityMat.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); @@ -490,15 +493,18 @@ void AerAccelerator::execute( {ExecutionInfo::DmKey, std::make_shared(std::move(dm))}}; buffer->addExtraInfo("exp-val-z", exp_val); - }*/ - else { + + } else { + assert(m_simtype == "statevector"); + // statevector // remove all measures, don't need them auto tmp = xacc::ir::asComposite(program->clone()); tmp->clear(); AER::reg_t measured_bits; InstructionIterator iter(program); + while (iter.hasNext()) { auto next = iter.next(); if (!next->isComposite() && next->name() != "Measure") { @@ -507,6 +513,7 @@ void AerAccelerator::execute( measured_bits.push_back(next->bits()[0]); } } + auto qobj_str = xacc_to_qobj->translate(tmp); nlohmann::json qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; qObjJson["config"]["method"] = "statevector"; @@ -514,7 +521,7 @@ void AerAccelerator::execute( AER::Statevector::State> stateVec; AER::RngEngine rng; AER::Qobj qobj(qObjJson); - // std::cout << "QObj:\n" << qobj_str << "\n"; + assert(qobj.circuits.size() == 1); auto circ = qobj.circuits[0]; // Output data container @@ -539,9 +546,8 @@ void AerAccelerator::execute( } stateVec.qreg().initialize_from_vector(intial_state); } - // std::cout << "Num op: " << circ.ops.size() << "\n"; + stateVec.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); - // std::cout << "Result: \n" << data.to_json().dump() << "\n"; const double exp_val = stateVec.qreg().expval_pauli( measured_bits, std::string(measured_bits.size(), 'Z')); @@ -574,17 +580,21 @@ void AerAccelerator::execute( void AerAccelerator::apply(std::shared_ptr buffer, std::shared_ptr inst) { + static AER::Statevector::State> stateVec; static auto provider = xacc::getIRProvider("quantum"); static AER::RngEngine rng; static std::set knownBuffers; + if (!xacc::container::contains(knownBuffers, buffer.get())) { stateVec.initialize_qreg(buffer->size()); knownBuffers.emplace(buffer.get()); } + if (inst->isComposite() || inst->isAnalog()) { xacc::error("Only gates are allowed."); } + xacc::info("Apply: " + inst->toString()); if (inst->name() != "Measure") { auto tempComp = provider->createComposite("tmp"); @@ -593,22 +603,13 @@ void AerAccelerator::apply(std::shared_ptr buffer, auto qObjJson = nlohmann::json::parse(qobj_str)["qObject"]; qObjJson["config"]["enable_truncation"] = false; AER::Qobj qobj(qObjJson); - // std::cout << "QObj:\n" << qobj_str << "\n"; assert(qobj.circuits.size() == 1); auto circ = qobj.circuits[0]; // Output data container AER::ExperimentResult data; - // std::cout << "Num op: " << circ.ops.size() << "\n"; stateVec.apply_ops(circ->ops.begin(), circ->ops.end(), data, rng); - // std::cout << "Result: \n" << data.to_json().dump() << "\n"; - // auto wavefn = stateVec.copy_to_vector(0); - // std::cout << "HOWDY: " << wavefn.size() << "\n"; - // for (int i = 0; i < wavefn.size(); ++i) { - // std::cout << wavefn[i] << "\n"; - // } } - // stateVec.add_creg_to_data(data); - // If it was a Measure op: + else { AER::reg_t measured_bits{inst->bits()[0]}; const auto probs = stateVec.qreg().probabilities(measured_bits); @@ -625,7 +626,7 @@ void AerAccelerator::apply(std::shared_ptr buffer, buffer->measure(inst->bits()[0], outcome); } } -/* + void IbmqNoiseModel::initialize(const HeterogeneousMap ¶ms) { m_nbQubits = 0; m_qubitT1.clear(); @@ -906,12 +907,14 @@ IbmqNoiseModel::getNoiseChannels(xacc::quantum::Gate &gate) const { std::string IbmqNoiseModel::toJson() const { // First, check if Qiskit is available, // try to use Qiskit util if possible. + /* const std::string noiseModelJson = xacc::aer::noiseModelFromBackendProperties(m_backendPropertiesJson); if (!noiseModelJson.empty()) { xacc::info("Qiskit generated noise model:\n" + noiseModelJson); return noiseModelJson; } + */ // No Qiskit, create the noise model by ourselves from the backend properties. // Aer noise model Json @@ -1036,7 +1039,7 @@ IbmqNoiseModel::averageTwoQubitGateFidelity() const { return result; } -*/ + std::string AerAccelerator::getNativeCode(std::shared_ptr program, const HeterogeneousMap &config) { @@ -1063,8 +1066,8 @@ class US_ABI_LOCAL AerActivator : public BundleActivator { void Start(BundleContext context) { auto xt = std::make_shared(); context.RegisterService(xt); - //context.RegisterService( - // std::make_shared()); + context.RegisterService( + std::make_shared()); } /** diff --git a/quantum/plugins/ibm/aer/accelerator/aer_accelerator.hpp b/quantum/plugins/ibm/aer/aer_accelerator.hpp similarity index 100% rename from quantum/plugins/ibm/aer/accelerator/aer_accelerator.hpp rename to quantum/plugins/ibm/aer/aer_accelerator.hpp diff --git a/quantum/plugins/ibm/aer/accelerator/aer_noise_model.hpp b/quantum/plugins/ibm/aer/aer_noise_model.hpp similarity index 100% rename from quantum/plugins/ibm/aer/accelerator/aer_noise_model.hpp rename to quantum/plugins/ibm/aer/aer_noise_model.hpp diff --git a/quantum/plugins/ibm/aer/py-aer/CMakeLists.txt b/quantum/plugins/ibm/aer/py-aer/CMakeLists.txt deleted file mode 100644 index e669750e8..000000000 --- a/quantum/plugins/ibm/aer/py-aer/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -set(LIBRARY_NAME xacc-py-aer-adapter) -find_package(Python COMPONENTS Interpreter Development) -get_filename_component(PYTHON_LIB_NAME ${Python_LIBRARIES} NAME) -configure_file(aer_python_adapter.in.cpp - ${CMAKE_BINARY_DIR}/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.cpp) -file(GLOB SRC ${CMAKE_BINARY_DIR}/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.cpp) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing -O2 -g -pipe -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wformat -fexceptions --param=ssp-buffer-size=4 -grecord-gcc-switches -mtune=native -D_GNU_SOURCE -fPIC -fwrapv") -else() - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing -O2 -g -pipe -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wformat -fexceptions --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=native -D_GNU_SOURCE -fPIC -fwrapv") -endif() -add_library(${LIBRARY_NAME} SHARED ${SRC}) - -if(Python_FOUND) - message(STATUS "${BoldGreen}Found Python version ${Python_VERSION}.${ColorReset}") - # Always install the Aer Pulse Python Adapter when having Python. - # Users may need to do `pip install qiskit` if they don't have Qiskit yet. - target_include_directories(${LIBRARY_NAME} PUBLIC . ${Python_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/tpls/pybind11/include ${CMAKE_BINARY_DIR}) - target_link_libraries(${LIBRARY_NAME} PRIVATE Python::Python) - - # Check if we have Qiskit installed - execute_process(COMMAND ${Python_EXECUTABLE} -c "import qiskit; print('Qiskit: ', qiskit.__version__)" RESULT_VARIABLE QISKIT_EXISTS) - if (QISKIT_EXISTS EQUAL "1") - message(STATUS "${BoldYellow}Qiskit not found. To use the Aer Pulse Simulator, please install Qiskit.${ColorReset}") - endif() -else() - message(STATUS "${BoldYellow}Python interpreter or development headers not found. Aer Pulse Simulator is disabled.${ColorReset}") -endif() - -if(APPLE) - set_target_properties(${LIBRARY_NAME} - PROPERTIES INSTALL_RPATH "@loader_path/../lib") - set_target_properties(${LIBRARY_NAME} - PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -else() - set_target_properties(${LIBRARY_NAME} - PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") - set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-rdynamic -shared") -endif() - -install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) diff --git a/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.hpp b/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.hpp deleted file mode 100644 index 0aae4a1b7..000000000 --- a/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include -#include - -namespace xacc { -namespace aer { -std::string runPulseSim(const std::string &hamJsonStr, double dt, - const std::vector &freqEst, - const std::vector &uChanLoRefs, - const std::string &qObjJson); -std::string -noiseModelFromBackendProperties(const std::string &backendPropertiesJson); -} // namespace AER -} // namespace xacc \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.in.cpp b/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.in.cpp deleted file mode 100644 index 54c45aae5..000000000 --- a/quantum/plugins/ibm/aer/py-aer/aer_python_adapter.in.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "aer_python_adapter.hpp" -#include -#include -#include -#include -#include -#include "xacc_config.hpp" - -namespace { -void initPython() { - static bool PythonInit = false; - if (!PythonInit) { - if (!XACC_IS_APPLE) { - // If not MacOs, preload Python lib to the address space. - // Note: we don't need to dlclose, just need to load the lib to prevent - // linking issue on Linux. - auto libPythonPreload = - dlopen("@PYTHON_LIB_NAME@", RTLD_LAZY | RTLD_GLOBAL); - } - try { - // This is implemented as a free-function, - // hence just try to start an interpreter, - // and ignore if the interpreter has been started. - pybind11::initialize_interpreter(); - } catch (std::exception &e) { - // std::cout << e.what(); - } - PythonInit = true; - } -} -} // namespace - -namespace xacc { -namespace aer { -std::string runPulseSim(const std::string &hamJsonStr, double dt, - const std::vector &freqEst, - const std::vector &uChanLoRefs, - const std::string &qObjJson) { - initPython(); - auto py_src = R"#( -import json, warnings -import numpy as np -from qiskit.providers.aer.pulse.system_models.hamiltonian_model import HamiltonianModel -from qiskit.providers.aer.pulse.system_models.pulse_system_model import PulseSystemModel -from qiskit.providers.aer.backends import PulseSimulator -from qiskit import qobj, pulse -from qiskit.compiler import assemble -from qiskit.qobj.converters import QobjToInstructionConverter -from qiskit.providers.models.backendconfiguration import UchannelLO -warnings.filterwarnings("ignore", category=RuntimeWarning, module="qiskit") -# Parse inputs to construct PulseSystemModel -ham_dict = json.loads(locals()["ham_json"]) -ham_model = HamiltonianModel.from_dict(ham_dict) -u_channel_lo = [] -for u_chan_ref in locals()["u_channel_lo_ref"]: - u_channel_lo.append([UchannelLO(int(u_chan_ref), 1.0+0.0j)]) - -system_model = PulseSystemModel(hamiltonian=ham_model, - u_channel_lo=u_channel_lo, - subsystem_list=locals()["subsystem_list"], - dt=locals()["dt"]) -backend_sim = PulseSimulator() -backend_sim.defaults().qubit_freq_est = locals()["qubit_freq_est"] -qobjDict = json.loads(locals()["qobj_json"]) -pulseQobj = qobj.PulseQobj.from_dict(qobjDict) -converter = QobjToInstructionConverter(pulseQobj.config.pulse_library) -run_config = pulseQobj.config.to_dict() -run_config.pop('pulse_library') -qubit_lo_freq = run_config.get('qubit_lo_freq') -if qubit_lo_freq: - run_config['qubit_lo_freq'] = [freq*1e9 for freq in qubit_lo_freq] -meas_lo_freq = run_config.get('meas_lo_freq') -if meas_lo_freq: - run_config['meas_lo_freq'] = [freq*1e9 for freq in meas_lo_freq] -programs = [] -for program in pulseQobj.experiments: - insts = [] - for inst in program.instructions: - insts.append(converter(inst)) - schedule = pulse.Schedule(*insts) - programs.append(schedule) - -# Reconstruct Pulse Obj for the AER simulator -pulse_qobj = assemble(programs, - backend=backend_sim, - meas_level=run_config['meas_level'], - meas_return=run_config['meas_return'], - memory_slots=run_config['memory_slots'], - shots=run_config['shots'], - meas_lo_freq=run_config['meas_lo_freq']) -result = backend_sim.run(pulse_qobj, system_model=system_model).result().to_dict() -# Set output (JSON of bitstring -> count map) -hex_to_count = result["results"][0]["data"]["counts"] -for hex_val in hex_to_count: - hex_to_count[hex_val] = int(hex_to_count[hex_val]) -state_vec = result["results"][0]["data"]["statevector"] -result_data = {"counts": hex_to_count, "statevector": state_vec } -result_json = json.dumps(result_data) -)#"; - // Check if Qiskit present. - try { - pybind11::module::import("qiskit"); - } catch (std::exception &e) { - std::cerr << e.what() << '\n'; - std::cerr << "Qiskit is not installed. Please install Qiskit to use the " - "Aer Pulse simulator.\n"; - throw; - } - - // Set variables: - auto locals = pybind11::dict(); - locals["ham_json"] = hamJsonStr; - locals["dt"] = dt; - locals["qubit_freq_est"] = freqEst; - locals["u_channel_lo_ref"] = uChanLoRefs; - - std::vector subSystemList(freqEst.size()); - std::iota(subSystemList.begin(), subSystemList.end(), 0); - locals["subsystem_list"] = subSystemList; - locals["qobj_json"] = qObjJson; - // Run the simulator: - pybind11::exec(py_src, pybind11::globals(), locals); - const auto result = locals["result_json"].cast(); - return result; -} - -std::string -noiseModelFromBackendProperties(const std::string &backendPropertiesJson) { - initPython(); - // Check if Qiskit present. - try { - pybind11::module::import("qiskit"); - } catch (std::exception &e) { - // No Qiskit can be found, returns an empty string: - // i.e. not able to use Qiskit to create the noise model... - return ""; - } - - auto py_src = R"#( -import json -from qiskit.providers.models import BackendProperties -from qiskit.providers.aer.noise import NoiseModel -backend_properties = json.loads(locals()["properties_json"]) -properties = BackendProperties.from_dict(backend_properties) -noise_model = NoiseModel.from_backend(properties) -noise_model_json = json.dumps(noise_model.to_dict(True)) -)#"; - - // Set variables: - auto locals = pybind11::dict(); - locals["properties_json"] = backendPropertiesJson; - try { - pybind11::exec(py_src, pybind11::globals(), locals); - const auto result = locals["noise_model_json"].cast(); - return result; - } catch (...) { - return ""; - } -} -} // namespace aer -} // namespace xacc diff --git a/quantum/plugins/ibm/aer/src/LICENSE.txt b/quantum/plugins/ibm/aer/src/LICENSE.txt deleted file mode 100644 index 7b641c3ab..000000000 --- a/quantum/plugins/ibm/aer/src/LICENSE.txt +++ /dev/null @@ -1,203 +0,0 @@ - Copyright 2018 IBM and its contributors - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 IBM and its contributors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/quantum/plugins/ibm/aer/src/controllers/aer_controller.hpp b/quantum/plugins/ibm/aer/src/controllers/aer_controller.hpp deleted file mode 100755 index a477a0fef..000000000 --- a/quantum/plugins/ibm/aer/src/controllers/aer_controller.hpp +++ /dev/null @@ -1,2003 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_controller_hpp_ -#define _aer_controller_hpp_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) || defined(__APPLE__) -#include -#elif defined(_WIN64) || defined(_WIN32) -// This is needed because windows.h redefine min()/max() so interferes with -// std::min/max -#define NOMINMAX -#include -#endif - -#ifdef _OPENMP -#include -#endif - -#ifdef AER_MPI -#include -#endif - -#include "framework/creg.hpp" -#include "framework/qobj.hpp" -#include "framework/results/experiment_result.hpp" -#include "framework/results/result.hpp" -#include "framework/rng.hpp" -#include "noise/noise_model.hpp" - -#include "transpile/cacheblocking.hpp" -#include "transpile/fusion.hpp" - -#include "simulators/density_matrix/densitymatrix_state.hpp" -#include "simulators/extended_stabilizer/extended_stabilizer_state.hpp" -#include "simulators/matrix_product_state/matrix_product_state.hpp" -#include "simulators/stabilizer/stabilizer_state.hpp" -#include "simulators/statevector/qubitvector.hpp" -#include "simulators/statevector/statevector_state.hpp" -#include "simulators/superoperator/superoperator_state.hpp" -#include "simulators/unitary/unitary_state.hpp" - -namespace AER { - -//========================================================================= -// AER::Controller class -//========================================================================= - -// This is the top level controller for the Qiskit-Aer simulator -// It manages execution of all the circuits in a QOBJ, parallelization, -// noise sampling from a noise model, and circuit optimizations. - -class Controller { -public: - Controller() { clear_parallelization(); } - - //----------------------------------------------------------------------- - // Execute qobj - //----------------------------------------------------------------------- - - // Load a QOBJ from a JSON file and execute on the State type - // class. - template - Result execute(const inputdata_t &qobj); - - Result execute(std::vector &circuits, - Noise::NoiseModel &noise_model, - const json_t &config); - - //----------------------------------------------------------------------- - // Config settings - //----------------------------------------------------------------------- - - // Load Controller, State and Data config from a JSON - // config settings will be passed to the State and Data classes - void set_config(const json_t &config); - - // Clear the current config - void clear_config(); - -protected: - //----------------------------------------------------------------------- - // Simulation types - //----------------------------------------------------------------------- - - // Simulation methods for the Qasm Controller - enum class Method { - automatic, - statevector, - density_matrix, - matrix_product_state, - stabilizer, - extended_stabilizer, - unitary, - superop - }; - - enum class Device { CPU, GPU, ThrustCPU }; - - // Simulation precision - enum class Precision { Double, Single }; - - const std::unordered_map method_names_ = { - {Method::automatic, "automatic"}, - {Method::statevector, "statevector"}, - {Method::density_matrix, "density_matrix"}, - {Method::matrix_product_state, "matrix_product_state"}, - {Method::stabilizer, "stabilizer"}, - {Method::extended_stabilizer, "extended_stabilizer"}, - {Method::unitary, "unitary"}, - {Method::superop, "superop"} - }; - - //----------------------------------------------------------------------- - // Config - //----------------------------------------------------------------------- - - // Timer type - using myclock_t = std::chrono::high_resolution_clock; - - // Validation threshold for validating states and operators - double validation_threshold_ = 1e-8; - - // Save counts as memory list - bool save_creg_memory_ = false; - - // Simulation method - Method method_ = Method::automatic; - - // Simulation device - Device sim_device_ = Device::CPU; - std::string sim_device_name_ = "CPU"; - - // Simulation precision - Precision sim_precision_ = Precision::Double; - - // Controller-level parameter for CH method - bool extended_stabilizer_measure_sampling_ = false; - - //----------------------------------------------------------------------- - // Circuit Execution - //----------------------------------------------------------------------- - - // Abstract method for executing a circuit. - // This method must initialize a state and return output data for - // the required number of shots. - void run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method,const json_t &config, ExperimentResult &result) const; - - //---------------------------------------------------------------- - // Run circuit helpers - //---------------------------------------------------------------- - - // Execute n-shots of a circuit on the input state - template - void run_circuit_helper(const Circuit &circ, const Noise::NoiseModel &noise, - const json_t &config, const Method method, - ExperimentResult &result) const; - - // Execute a single shot a of circuit by initializing the state vector, - // running all ops in circ, and updating data with - // simulation output. - template - void run_single_shot(const Circuit &circ, State_t &state, - ExperimentResult &result, RngEngine &rng) const; - - // Execute a single shot a of circuit by initializing the state vector, - // running all ops in circ, and updating data with - // simulation output. - template - void run_with_sampling(const Circuit &circ, - State_t &state, - ExperimentResult &result, - RngEngine &rng, - const uint_t block_bits, - const uint_t shots) const; - - // Execute multiple shots a of circuit by initializing the state vector, - // running all ops in circ, and updating data with - // simulation output. Will use measurement sampling if possible - template - void run_circuit_without_sampled_noise(Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config, - const Method method, - ExperimentResult &result) const; - - template - void run_circuit_with_sampled_noise(const Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config, - const Method method, - ExperimentResult &result) const; - - //---------------------------------------------------------------- - // Measurement - //---------------------------------------------------------------- - - // Sample measurement outcomes for the input measure ops from the - // current state of the input State_t - template - void measure_sampler(InputIterator first_meas, InputIterator last_meas, - uint_t shots, State_t &state, ExperimentResult &result, - RngEngine &rng , int_t shot_index = -1) const; - - // Check if measure sampling optimization is valid for the input circuit - // for the given method. This checks if operation types before - // the first measurement in the circuit prevent sampling - bool check_measure_sampling_opt(const Circuit &circ, - const Method method) const; - - // Save count data - void save_count_data(ExperimentResult &result, - const ClassicalRegister &creg) const; - - //------------------------------------------------------------------------- - // State validation - //------------------------------------------------------------------------- - - // Return True if the operations in the circuit and noise model are valid - // for execution on the given method, and that the required memory is less - // than the maximum allowed memory, otherwise return false. - // If `throw_except` is true an exception will be thrown on the return false - // case listing the invalid instructions in the circuit or noise model, or - // the required memory. - bool validate_method(Method method, - const Circuit &circ, - const Noise::NoiseModel &noise, - bool throw_except = false) const; - - template - bool validate_state(const state_t &state, const Circuit &circ, - const Noise::NoiseModel &noise, - bool throw_except = false) const; - - // Return an estimate of the required memory for a circuit. - size_t required_memory_mb(const Circuit &circuit, - const Noise::NoiseModel &noise, - const Method method) const; - - //---------------------------------------------------------------- - // Utility functions - //---------------------------------------------------------------- - - // Return a vector of simulation methods for each circuit. - // If the default method is automatic this will be computed based on the - // circuit and noise model. - // The noise model will be modified to enable superop or kraus sampling - // methods if required by the chosen methods. - std::vector - simulation_methods(std::vector &circuits, - Noise::NoiseModel &noise_model) const; - - // Return the simulation method to use based on the input circuit - // and noise model - Controller::Method - automatic_simulation_method(const Circuit &circ, - const Noise::NoiseModel &noise_model) const; - - // Return a fusion transpilation pass configured for the current - // method, circuit and config - Transpile::Fusion transpile_fusion(Method method, - const Operations::OpSet &opset, - const json_t &config) const; - - // Return cache blocking transpiler pass - Transpile::CacheBlocking - transpile_cache_blocking(Controller::Method method, - const Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config) const; - - //return maximum number of qubits for matrix - int_t get_max_matrix_qubits(const Circuit &circ) const; - int_t get_matrix_bits(const Operations::Op& op) const; - - //----------------------------------------------------------------------- - // Parallelization Config - //----------------------------------------------------------------------- - - // Set OpenMP thread settings to default values - void clear_parallelization(); - - // Set parallelization for experiments - void - set_parallelization_experiments(const std::vector &circuits, - const Noise::NoiseModel &noise, - const std::vector &methods); - - // Set circuit parallelization - void set_parallelization_circuit(const Circuit &circ, - const Noise::NoiseModel &noise, - const Method method); - - bool multiple_chunk_required(const Circuit &circuit, - const Noise::NoiseModel &noise, - const Method method) const; - - bool multiple_shots_required(const Circuit &circuit, - const Noise::NoiseModel &noise, - const Method method) const; - - void save_exception_to_results(Result &result, const std::exception &e) const; - - // Get system memory size - size_t get_system_memory_mb(); - size_t get_gpu_memory_mb(); - - size_t get_min_memory_mb() const { - if (sim_device_ == Device::GPU && num_gpus_ > 0) { - return max_gpu_memory_mb_ / num_gpus_; // return per GPU memory size - } - return max_memory_mb_; - } - - // The maximum number of threads to use for various levels of parallelization - int max_parallel_threads_; - - // Parameters for parallelization management in configuration - int max_parallel_experiments_; - int max_parallel_shots_; - size_t max_memory_mb_; - size_t max_gpu_memory_mb_; - int num_gpus_; // max number of GPU per process - - // use explicit parallelization - bool explicit_parallelization_; - - // Parameters for parallelization management for experiments - int parallel_experiments_; - int parallel_shots_; - int parallel_state_update_; - - bool parallel_nested_ = false; - - //max number of states can be stored on memory for batched multi-shots/experiments optimization - int max_batched_states_; - - // max number of qubits in given circuits - int max_qubits_; - - // results are stored independently in each process if true - bool accept_distributed_results_ = true; - - // process information (MPI) - int myrank_ = 0; - int num_processes_ = 1; - int num_process_per_experiment_ = 1; - - uint_t cache_block_qubit_ = 0; - - //multi-chunks are required to simulate circuits - bool multi_chunk_required_ = false; - - //config setting for multi-shot parallelization - bool batched_shots_gpu_ = true; - int_t batched_shots_gpu_max_qubits_ = 16; //multi-shot parallelization is applied if qubits is less than max qubits - bool enable_batch_multi_shots_ = false; //multi-shot parallelization can be applied - - //settings for cuStateVec - bool cuStateVec_enable_ = false; -}; - -//========================================================================= -// Implementations -//========================================================================= - -//------------------------------------------------------------------------- -// Config settings -//------------------------------------------------------------------------- - -void Controller::set_config(const json_t &config) { - - // Load validation threshold - JSON::get_value(validation_threshold_, "validation_threshold", config); - - // Load config for memory (creg list data) - JSON::get_value(save_creg_memory_, "memory", config); - -#ifdef _OPENMP - // Load OpenMP maximum thread settings - if (JSON::check_key("max_parallel_threads", config)) - JSON::get_value(max_parallel_threads_, "max_parallel_threads", config); - if (JSON::check_key("max_parallel_experiments", config)) - JSON::get_value(max_parallel_experiments_, "max_parallel_experiments", - config); - if (JSON::check_key("max_parallel_shots", config)) - JSON::get_value(max_parallel_shots_, "max_parallel_shots", config); - // Limit max threads based on number of available OpenMP threads - auto omp_threads = omp_get_max_threads(); - max_parallel_threads_ = (max_parallel_threads_ > 0) - ? std::min(max_parallel_threads_, omp_threads) - : std::max(1, omp_threads); -#else - // No OpenMP so we disable parallelization - max_parallel_threads_ = 1; - max_parallel_shots_ = 1; - max_parallel_experiments_ = 1; - parallel_nested_ = false; -#endif - - // Load configurations for parallelization - - if (JSON::check_key("max_memory_mb", config)) { - JSON::get_value(max_memory_mb_, "max_memory_mb", config); - } - - // for debugging - if (JSON::check_key("_parallel_experiments", config)) { - JSON::get_value(parallel_experiments_, "_parallel_experiments", config); - explicit_parallelization_ = true; - } - - // for debugging - if (JSON::check_key("_parallel_shots", config)) { - JSON::get_value(parallel_shots_, "_parallel_shots", config); - explicit_parallelization_ = true; - } - - // for debugging - if (JSON::check_key("_parallel_state_update", config)) { - JSON::get_value(parallel_state_update_, "_parallel_state_update", config); - explicit_parallelization_ = true; - } - - if (explicit_parallelization_) { - parallel_experiments_ = std::max({parallel_experiments_, 1}); - parallel_shots_ = std::max({parallel_shots_, 1}); - parallel_state_update_ = std::max({parallel_state_update_, 1}); - } - - if (JSON::check_key("accept_distributed_results", config)) { - JSON::get_value(accept_distributed_results_, "accept_distributed_results", - config); - } - - // enable multiple qregs if cache blocking is enabled - cache_block_qubit_ = 0; - if (JSON::check_key("blocking_qubits", config)) { - JSON::get_value(cache_block_qubit_, "blocking_qubits", config); - } - - //enable batched multi-shots/experiments optimization - if(JSON::check_key("batched_shots_gpu", config)) { - JSON::get_value(batched_shots_gpu_, "batched_shots_gpu", config); - } - if(JSON::check_key("batched_shots_gpu_max_qubits", config)) { - JSON::get_value(batched_shots_gpu_max_qubits_, "batched_shots_gpu_max_qubits", config); - } - - //cuStateVec configs - cuStateVec_enable_ = false; - if(JSON::check_key("cuStateVec_enable", config)) { - JSON::get_value(cuStateVec_enable_, "cuStateVec_enable", config); - } - - // Override automatic simulation method with a fixed method - std::string method; - if (JSON::get_value(method, "method", config)) { - if (method == "statevector") { - method_ = Method::statevector; - } else if (method == "density_matrix") { - method_ = Method::density_matrix; - } else if (method == "stabilizer") { - method_ = Method::stabilizer; - } else if (method == "extended_stabilizer") { - method_ = Method::extended_stabilizer; - } else if (method == "matrix_product_state") { - method_ = Method::matrix_product_state; - } else if (method == "unitary") { - method_ = Method::unitary; - } else if (method == "superop") { - method_ = Method::superop; - } else if (method != "automatic") { - throw std::runtime_error(std::string("Invalid simulation method (") + - method + std::string(").")); - } - } - - if(method_ == Method::density_matrix || method_ == Method::unitary) - batched_shots_gpu_max_qubits_ /= 2; - - // Override automatic simulation method with a fixed method - if (JSON::get_value(sim_device_name_, "device", config)) { - if (sim_device_name_ == "CPU") { - sim_device_ = Device::CPU; - } else if (sim_device_name_ == "Thrust") { -#ifndef AER_THRUST_CPU - throw std::runtime_error( - "Simulation device \"Thrust\" is not supported on this system"); -#else - sim_device_ = Device::ThrustCPU; -#endif - } else if (sim_device_name_ == "GPU") { -#ifndef AER_THRUST_CUDA - throw std::runtime_error( - "Simulation device \"GPU\" is not supported on this system"); -#else - -#ifndef AER_CUSTATEVEC - if(cuStateVec_enable_){ - //Aer is not built for cuStateVec - throw std::runtime_error( - "Simulation device \"GPU\" does not supported cuStateVec on this system"); - } -#endif - int nDev; - if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - cudaGetLastError(); - throw std::runtime_error("No CUDA device available!"); - } - sim_device_ = Device::GPU; -#endif - } - else { - throw std::runtime_error(std::string("Invalid simulation device (\"") + - sim_device_name_ + std::string("\").")); - } - } - - std::string precision; - if (JSON::get_value(precision, "precision", config)) { - if (precision == "double") { - sim_precision_ = Precision::Double; - } else if (precision == "single") { - sim_precision_ = Precision::Single; - } else { - throw std::runtime_error(std::string("Invalid simulation precision (") + - precision + std::string(").")); - } - } -} - -void Controller::clear_config() { - clear_parallelization(); - validation_threshold_ = 1e-8; - method_ = Method::automatic; - sim_device_ = Device::CPU; - sim_precision_ = Precision::Double; -} - -void Controller::clear_parallelization() { - max_parallel_threads_ = 0; - max_parallel_experiments_ = 1; - max_parallel_shots_ = 0; - max_batched_states_ = 1; - - parallel_experiments_ = 1; - parallel_shots_ = 1; - parallel_state_update_ = 1; - parallel_nested_ = false; - - num_process_per_experiment_ = 1; - - num_gpus_ = 0; - - explicit_parallelization_ = false; - max_memory_mb_ = get_system_memory_mb(); - max_gpu_memory_mb_ = get_gpu_memory_mb(); -} - -void Controller::set_parallelization_experiments( - const std::vector &circuits, - const Noise::NoiseModel &noise, - const std::vector &methods) -{ - std::vector required_memory_mb_list(circuits.size()); - max_qubits_ = 0; - for (size_t j = 0; j < circuits.size(); j++) { - if(circuits[j].num_qubits > max_qubits_) - max_qubits_ = circuits[j].num_qubits; - required_memory_mb_list[j] = required_memory_mb(circuits[j], noise, methods[j]); - } - std::sort(required_memory_mb_list.begin(), required_memory_mb_list.end(), - std::greater<>()); - - //set max batchable number of circuits - if(batched_shots_gpu_){ - if(required_memory_mb_list[0] == 0 || max_qubits_ == 0) - max_batched_states_ = 1; - else{ - if(sim_device_ == Device::GPU){ - max_batched_states_ = ((max_gpu_memory_mb_/num_gpus_*8/10) / required_memory_mb_list[0])*num_gpus_; - } - else{ - max_batched_states_ = (max_memory_mb_*8/10) / required_memory_mb_list[0]; - } - } - } - if(max_qubits_ == 0) - max_qubits_ = 1; - - if(explicit_parallelization_ ) - return; - - if(circuits.size() == 1){ - parallel_experiments_ = 1; - return; - } - - // Use a local variable to not override stored maximum based - // on currently executed circuits - const auto max_experiments = - (max_parallel_experiments_ > 0) - ? std::min({max_parallel_experiments_, max_parallel_threads_}) - : max_parallel_threads_; - - if (max_experiments == 1) { - // No parallel experiment execution - parallel_experiments_ = 1; - return; - } - - // If memory allows, execute experiments in parallel - size_t total_memory = 0; - int parallel_experiments = 0; - for (size_t required_memory_mb : required_memory_mb_list) { - total_memory += required_memory_mb; - if (total_memory > max_memory_mb_) - break; - ++parallel_experiments; - } - - if (parallel_experiments <= 0) - throw std::runtime_error( - "a circuit requires more memory than max_memory_mb."); - parallel_experiments_ = - std::min({parallel_experiments, max_experiments, - max_parallel_threads_, static_cast(circuits.size())}); -} - -void Controller::set_parallelization_circuit(const Circuit &circ, - const Noise::NoiseModel &noise, - const Method method) -{ - enable_batch_multi_shots_ = false; - if(batched_shots_gpu_ && sim_device_ == Device::GPU && - circ.shots > 1 && max_batched_states_ >= num_gpus_ && - batched_shots_gpu_max_qubits_ >= circ.num_qubits ){ - enable_batch_multi_shots_ = true; - } - - if(sim_device_ == Device::GPU && cuStateVec_enable_){ - enable_batch_multi_shots_ = false; //cuStateVec does not support batch execution of multi-shots - return; - } - - if(explicit_parallelization_) - return; - - // Check for trivial parallelization conditions - switch (method) { - case Method::statevector: - case Method::stabilizer: - case Method::unitary: - case Method::matrix_product_state: { - if (circ.shots == 1 || num_process_per_experiment_ > 1 || - (!noise.has_quantum_errors() && - check_measure_sampling_opt(circ, method))) { - parallel_shots_ = 1; - parallel_state_update_ = - std::max({1, max_parallel_threads_ / parallel_experiments_}); - return; - } - break; - } - case Method::density_matrix: - case Method::superop: { - if (circ.shots == 1 || num_process_per_experiment_ > 1 || - check_measure_sampling_opt(circ, method)) { - parallel_shots_ = 1; - parallel_state_update_ = - std::max({1, max_parallel_threads_ / parallel_experiments_}); - return; - } - break; - } - case Method::extended_stabilizer: - break; - default: - throw std::invalid_argument("Cannot set parallelization for unresolved method."); - } - - // Use a local variable to not override stored maximum based - // on currently executed circuits - const auto max_shots = - (max_parallel_shots_ > 0) - ? std::min({max_parallel_shots_, max_parallel_threads_}) - : max_parallel_threads_; - - // If we are executing circuits in parallel we disable - // parallel shots - if (max_shots == 1 || parallel_experiments_ > 1) { - parallel_shots_ = 1; - } else { - // Parallel shots is > 1 - // Limit parallel shots by available memory and number of shots - // And assign the remaining threads to state update - int circ_memory_mb = - required_memory_mb(circ, noise, method) / num_process_per_experiment_; - size_t mem_size = (sim_device_ == Device::GPU) ? max_gpu_memory_mb_ : max_memory_mb_; - if (mem_size < circ_memory_mb) - throw std::runtime_error( - "a circuit requires more memory than max_memory_mb."); - // If circ memory is 0, set it to 1 so that we don't divide by zero - circ_memory_mb = std::max({1, circ_memory_mb}); - - int shots = circ.shots; - parallel_shots_ = std::min( - {static_cast(mem_size/(circ_memory_mb*2)), max_shots, shots}); - } - parallel_state_update_ = - (parallel_shots_ > 1) - ? std::max({1, max_parallel_threads_ / parallel_shots_}) - : std::max({1, max_parallel_threads_ / parallel_experiments_}); -} - -bool Controller::multiple_chunk_required(const Circuit &circ, - const Noise::NoiseModel &noise, - const Method method) const -{ - if (circ.num_qubits < 3) - return false; - if (cache_block_qubit_ >= 2 && cache_block_qubit_ < circ.num_qubits) - return true; - - if(num_process_per_experiment_ == 1 && sim_device_ == Device::GPU && num_gpus_ > 0){ - return (max_gpu_memory_mb_ / num_gpus_ < required_memory_mb(circ, noise, method)); - } - if(num_process_per_experiment_ > 1){ - size_t total_mem = max_memory_mb_; - if(sim_device_ == Device::GPU) - total_mem += max_gpu_memory_mb_; - if(total_mem*num_process_per_experiment_ > required_memory_mb(circ, noise, method)) - return true; - } - - return false; -} - -bool Controller::multiple_shots_required(const Circuit &circ, - const Noise::NoiseModel &noise, - const Method method) const -{ - if (circ.shots < 2) - return false; - if (method == Method::density_matrix || - method == Method::superop || - method == Method::unitary) { - return false; - } - - bool can_sample = check_measure_sampling_opt(circ, method); - - if (noise.is_ideal()){ - return !can_sample; - } - - return true; -} - -size_t Controller::get_system_memory_mb() -{ - size_t total_physical_memory = Utils::get_system_memory_mb(); -#ifdef AER_MPI - // get minimum memory size per process - uint64_t locMem, minMem; - locMem = total_physical_memory; - MPI_Allreduce(&locMem, &minMem, 1, MPI_UINT64_T, MPI_MIN, MPI_COMM_WORLD); - total_physical_memory = minMem; -#endif - - return total_physical_memory; -} - -size_t Controller::get_gpu_memory_mb() { - size_t total_physical_memory = 0; -#ifdef AER_THRUST_CUDA - int iDev, nDev, j; - if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - cudaGetLastError(); - nDev = 0; - } - for (iDev = 0; iDev < nDev; iDev++) { - size_t freeMem, totalMem; - cudaSetDevice(iDev); - cudaMemGetInfo(&freeMem, &totalMem); - total_physical_memory += totalMem; - } - num_gpus_ = nDev; -#endif - -#ifdef AER_MPI - // get minimum memory size per process - uint64_t locMem, minMem; - locMem = total_physical_memory; - MPI_Allreduce(&locMem, &minMem, 1, MPI_UINT64_T, MPI_MIN, MPI_COMM_WORLD); - total_physical_memory = minMem; - - int t = num_gpus_; - MPI_Allreduce(&t, &num_gpus_, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); -#endif - - return total_physical_memory >> 20; -} - - -Transpile::CacheBlocking -Controller::transpile_cache_blocking(Controller::Method method, const Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config) const -{ - Transpile::CacheBlocking cache_block_pass; - - const bool is_matrix = (method == Method::density_matrix - || method == Method::unitary); - const auto complex_size = (sim_precision_ == Precision::Single) - ? sizeof(std::complex) - : sizeof(std::complex); - - cache_block_pass.set_num_processes(num_process_per_experiment_); - cache_block_pass.set_config(config); - - if (!cache_block_pass.enabled()) { - // if blocking is not set by config, automatically set if required - if (multiple_chunk_required(circ, noise, method)) { - int nplace = num_process_per_experiment_; - if(sim_device_ == Device::GPU && num_gpus_ > 0) - nplace *= num_gpus_; - cache_block_pass.set_blocking(circ.num_qubits, get_min_memory_mb() << 20, - nplace, complex_size, is_matrix); - } - } - return cache_block_pass; -} - -//------------------------------------------------------------------------- -// Qobj execution -//------------------------------------------------------------------------- -template -Result Controller::execute(const inputdata_t &input_qobj) { -#ifdef AER_MPI - MPI_Comm_size(MPI_COMM_WORLD, &num_processes_); - MPI_Comm_rank(MPI_COMM_WORLD, &myrank_); -#endif - - // Load QOBJ in a try block so we can catch parsing errors and still return - // a valid JSON output containing the error message. - try { - // Start QOBJ timer - auto timer_start = myclock_t::now(); - - // Initialize QOBJ - Qobj qobj(input_qobj); - auto qobj_time_taken = - std::chrono::duration(myclock_t::now() - timer_start).count(); - - // Set config - set_config(qobj.config); - - // Run qobj circuits - auto result = execute(qobj.circuits, qobj.noise_model, qobj.config); - - // Add QOBJ loading time - result.metadata.add(qobj_time_taken, "time_taken_load_qobj"); - - // Get QOBJ id and pass through header to result - result.qobj_id = qobj.id; - if (!qobj.header.empty()) { - result.header = qobj.header; - } - - // Stop the timer and add total timing data including qobj parsing - auto time_taken = - std::chrono::duration(myclock_t::now() - timer_start).count(); - result.metadata.add(time_taken, "time_taken"); - return result; - } catch (std::exception &e) { - // qobj was invalid, return valid output containing error message - Result result; - - result.status = Result::Status::error; - result.message = std::string("Failed to load qobj: ") + e.what(); - return result; - } -} - -//------------------------------------------------------------------------- -// Experiment execution -//------------------------------------------------------------------------- - -Result Controller::execute(std::vector &circuits, - Noise::NoiseModel &noise_model, - const json_t &config) -{ - // Start QOBJ timer - auto timer_start = myclock_t::now(); - - // Determine simulation method for each circuit - // and enable required noise sampling methods - auto methods = simulation_methods(circuits, noise_model); - - // Initialize Result object for the given number of experiments - Result result(circuits.size()); - - // Execute each circuit in a try block - try { - //check if multi-chunk distribution is required - bool multi_chunk_required_ = false; - for (size_t j = 0; j < circuits.size(); j++){ - if(circuits[j].num_qubits > 0){ - if(multiple_chunk_required(circuits[j], noise_model, methods[j])) - multi_chunk_required_ = true; - } - } - if(multi_chunk_required_) - num_process_per_experiment_ = num_processes_; - else - num_process_per_experiment_ = 1; - - // set parallelization for experiments - try { - // catch exception raised by required_memory_mb because of invalid - // simulation method - set_parallelization_experiments(circuits, noise_model, methods); - } catch (std::exception &e) { - save_exception_to_results(result, e); - } - -#ifdef _OPENMP - result.metadata.add(true, "omp_enabled"); -#else - result.metadata.add(false, "omp_enabled"); -#endif - result.metadata.add(parallel_experiments_, "parallel_experiments"); - result.metadata.add(max_memory_mb_, "max_memory_mb"); - result.metadata.add(max_gpu_memory_mb_, "max_gpu_memory_mb"); - - // store rank and number of processes, if no distribution rank=0 procs=1 is - // set - result.metadata.add(num_process_per_experiment_, "num_processes_per_experiments"); - result.metadata.add(num_processes_, "num_mpi_processes"); - result.metadata.add(myrank_, "mpi_rank"); - -#ifdef _OPENMP - // Check if circuit parallelism is nested with one of the others - if (parallel_experiments_ > 1 && - parallel_experiments_ < max_parallel_threads_) { - // Nested parallel experiments - parallel_nested_ = true; - - //nested should be set to zero if num_threads clause will be used - omp_set_nested(0); - - result.metadata.add(parallel_nested_, "omp_nested"); - } else { - parallel_nested_ = false; - } -#endif - -#ifdef AER_MPI - //average random seed to set the same seed to each process (when seed_simulator is not set) - if(num_processes_ > 1){ - reg_t seeds(circuits.size()); - reg_t avg_seeds(circuits.size()); - for(int_t i=0;i(timer_stop - timer_start).count(); - result.metadata.add(time_taken, "time_taken_execute"); - } - // If execution failed return valid output reporting error - catch (std::exception &e) { - result.status = Result::Status::error; - result.message = e.what(); - } - return result; -} - -void Controller::save_count_data(ExperimentResult &result, - const ClassicalRegister &creg) const { - if (creg.memory_size() > 0) { - std::string memory_hex = creg.memory_hex(); - result.data.add_accum(static_cast(1ULL), "counts", memory_hex); - if (save_creg_memory_) { - result.data.add_list(std::move(memory_hex), "memory"); - } - } -} - -//------------------------------------------------------------------------- -// Base class override -//------------------------------------------------------------------------- -void Controller::run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method,const json_t &config, ExperimentResult &result) const -{ - // Run the circuit - switch (method) { - case Method::statevector: { - if (sim_device_ == Device::CPU) { - // Chunk based simualtion - if (sim_precision_ == Precision::Double) { - // Double-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, Method::statevector, result); - } else { - // Single-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, Method::statevector, result); - } - } else { -#ifdef AER_THRUST_SUPPORTED - // Chunk based simulation - if (sim_precision_ == Precision::Double) { - // Double-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, Method::statevector, result); - } else { - // Single-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, Method::statevector, result); - } -#endif - } - } - case Method::density_matrix: { - if (sim_device_ == Device::CPU) { - if (sim_precision_ == Precision::Double) { - // Double-precision density matrix simulation - return run_circuit_helper< - DensityMatrix::State>>( - circ, noise, config, Method::density_matrix, result); - } else { - // Single-precision density matrix simulation - return run_circuit_helper< - DensityMatrix::State>>( - circ, noise, config, Method::density_matrix, result); - } - } else { -#ifdef AER_THRUST_SUPPORTED - if (sim_precision_ == Precision::Double) { - // Double-precision density matrix simulation - return run_circuit_helper< - DensityMatrix::State>>( - circ, noise, config, Method::density_matrix, result); - } else { - // Single-precision density matrix simulation - return run_circuit_helper< - DensityMatrix::State>>( - circ, noise, config, Method::density_matrix, result); - } -#endif - } - } - case Method::unitary: { - if (sim_device_ == Device::CPU) { - if (sim_precision_ == Precision::Double) { - // Double-precision unitary simulation - return run_circuit_helper< - QubitUnitary::State>>( - circ, noise, config, Method::unitary, result); - } else { - // Single-precision unitary simulation - return run_circuit_helper< - QubitUnitary::State>>( - circ, noise, config, Method::unitary, result); - } - } else { -#ifdef AER_THRUST_SUPPORTED - if (sim_precision_ == Precision::Double) { - // Double-precision unitary simulation - return run_circuit_helper< - QubitUnitary::State>>( - circ, noise, config, Method::unitary, result); - } else { - // Single-precision unitary simulation - return run_circuit_helper< - QubitUnitary::State>>( - circ, noise, config, Method::unitary, result); - } -#endif - } - } - case Method::superop: { - if (sim_precision_ == Precision::Double) { - return run_circuit_helper< - QubitSuperoperator::State>>( - circ, noise, config, Method::superop, result); - } else { - return run_circuit_helper< - QubitSuperoperator::State>>( - circ, noise, config, Method::superop, result); - } - } - case Method::stabilizer: - // Stabilizer simulation - // TODO: Stabilizer doesn't yet support custom state initialization - return run_circuit_helper( - circ, noise, config, Method::stabilizer, result); - case Method::extended_stabilizer: - return run_circuit_helper( - circ, noise, config, Method::extended_stabilizer, result); - case Method::matrix_product_state: - return run_circuit_helper( - circ, noise, config, Method::matrix_product_state, result); - default: - throw std::runtime_error("Controller:Invalid simulation method"); - } -} - -//------------------------------------------------------------------------- -// Utility methods -//------------------------------------------------------------------------- - -size_t Controller::required_memory_mb(const Circuit &circ, - const Noise::NoiseModel &noise, - const Method method) const { - switch (method) { - case Method::statevector: { - if (sim_precision_ == Precision::Single) { - Statevector::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } else { - Statevector::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - } - case Method::density_matrix: { - if (sim_precision_ == Precision::Single) { - DensityMatrix::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } else { - DensityMatrix::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - } - case Method::unitary: { - if (sim_precision_ == Precision::Single) { - QubitUnitary::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } else { - QubitUnitary::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - } - case Method::superop: { - if (sim_precision_ == Precision::Single) { - QubitSuperoperator::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } else { - QubitSuperoperator::State> state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - } - case Method::stabilizer: { - Stabilizer::State state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - case Method::extended_stabilizer: { - ExtendedStabilizer::State state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - case Method::matrix_product_state: { - MatrixProductState::State state; - return state.required_memory_mb(circ.num_qubits, circ.ops); - } - default: - // We shouldn't get here, so throw an exception if we do - throw std::runtime_error("Controller: Invalid simulation method"); - } -} - -Transpile::Fusion Controller::transpile_fusion(Method method, - const Operations::OpSet &opset, - const json_t &config) const { - Transpile::Fusion fusion_pass; - fusion_pass.set_parallelization(parallel_state_update_); - - if (opset.contains(Operations::OpType::superop)) { - fusion_pass.allow_superop = true; - } - if (opset.contains(Operations::OpType::kraus)) { - fusion_pass.allow_kraus = true; - } - switch (method) { - case Method::density_matrix: - case Method::superop: { - // Halve the default threshold and max fused qubits for density matrix - fusion_pass.threshold /= 2; - fusion_pass.max_qubit /= 2; - break; - } - case Method::matrix_product_state: { - fusion_pass.active = false; - return fusion_pass; // Do not allow the config to set active for MPS - } - case Method::statevector: { - if (fusion_pass.allow_kraus) { - // Halve default max fused qubits for Kraus noise fusion - fusion_pass.max_qubit /= 2; - } - break; - } - case Method::unitary: { - // max_qubit is the same with statevector - fusion_pass.threshold /= 2; - break; - } - default: { - fusion_pass.active = false; - return fusion_pass; - } - } - // Override default fusion settings with custom config - fusion_pass.set_config(config); - return fusion_pass; -} - -//------------------------------------------------------------------------- -// Run circuit helpers -//------------------------------------------------------------------------- - -template -void Controller::run_circuit_helper(const Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config, - const Method method, - ExperimentResult &result) const -{ - // Start individual circuit timer - auto timer_start = myclock_t::now(); // state circuit timer - - // Initialize circuit json return - result.legacy_data.set_config(config); - - // Execute in try block so we can catch errors and return the error message - // for individual circuit failures. - try { - // Rng engine (this one is used to add noise on circuit) - RngEngine rng; - rng.set_seed(circ.seed); - - // Output data container - result.set_config(config); - result.metadata.add(method_names_.at(method), "method"); - if (method == Method::statevector || method == Method::density_matrix || - method == Method::unitary) { - result.metadata.add(sim_device_name_, "device"); - } else { - result.metadata.add("CPU", "device"); - } - - // Circuit qubit metadata - result.metadata.add(circ.num_qubits, "num_qubits"); - result.metadata.add(circ.num_memory, "num_clbits"); - result.metadata.add(circ.qubits(), "active_input_qubits"); - result.metadata.add(circ.qubit_map(), "input_qubit_map"); - result.metadata.add(circ.remapped_qubits, "remapped_qubits"); - - // Add measure sampling to metadata - // Note: this will set to `true` if sampling is enabled for the circuit - result.metadata.add(false, "measure_sampling"); - result.metadata.add(false, "batched_shots_optimization"); - - if(circ.num_qubits > 0){ //do nothing for query steps - // Choose execution method based on noise and method - Circuit opt_circ; - bool noise_sampling = false; - - // Ideal circuit - if (noise.is_ideal()) { - opt_circ = circ; - result.metadata.add("ideal", "noise"); - } - // Readout error only - else if (noise.has_quantum_errors() == false) { - opt_circ = noise.sample_noise(circ, rng); - result.metadata.add("readout", "noise"); - } - // Superop noise sampling - else if (method == Method::density_matrix || method == Method::superop) { - // Sample noise using SuperOp method - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::superop); - result.metadata.add("superop", "noise"); - } - // Kraus noise sampling - else if (noise.opset().contains(Operations::OpType::kraus) || - noise.opset().contains(Operations::OpType::superop)) { - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::kraus); - result.metadata.add("kraus", "noise"); - } - // General circuit noise sampling - else { - if(enable_batch_multi_shots_ && !multi_chunk_required_){ - //batched optimization samples noise at runtime - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::circuit, true); - } - else{ - noise_sampling = true; - } - result.metadata.add("circuit", "noise"); - } - - if(noise_sampling){ - run_circuit_with_sampled_noise(circ, noise, config, method, result); - } - else{ - // Run multishot simulation without noise sampling - run_circuit_without_sampled_noise(opt_circ, noise, config, method, result); - } - } - - // Report success - result.status = ExperimentResult::Status::completed; - - // Pass through circuit header and add metadata - result.header = circ.header; - result.shots = circ.shots; - result.seed = circ.seed; - result.metadata.add(parallel_shots_, "parallel_shots"); - result.metadata.add(parallel_state_update_, "parallel_state_update"); - - // Add timer data - auto timer_stop = myclock_t::now(); // stop timer - double time_taken = - std::chrono::duration(timer_stop - timer_start).count(); - result.time_taken = time_taken; - } - // If an exception occurs during execution, catch it and pass it to the output - catch (std::exception &e) { - result.status = ExperimentResult::Status::error; - result.message = e.what(); - } -} - -template -void Controller::run_single_shot(const Circuit &circ, State_t &state, - ExperimentResult &result, - RngEngine &rng) const { - state.initialize_qreg(circ.num_qubits); - state.initialize_creg(circ.num_memory, circ.num_registers); - state.apply_ops(circ.ops.cbegin(), circ.ops.cend(), result, rng, true); - save_count_data(result, state.creg()); -} - -template -void Controller::run_with_sampling(const Circuit &circ, - State_t &state, - ExperimentResult &result, - RngEngine &rng, - const uint_t block_bits, - const uint_t shots) const { - auto& ops = circ.ops; - auto first_meas = circ.first_measure_pos; // Position of first measurement op - bool final_ops = (first_meas == ops.size()); - - // allocate qubit register - state.allocate(circ.num_qubits, block_bits); - - // Run circuit instructions before first measure - state.initialize_qreg(circ.num_qubits); - state.initialize_creg(circ.num_memory, circ.num_registers); - - state.apply_ops(ops.cbegin(), ops.cbegin() + first_meas, result, rng, final_ops); - - // Get measurement operations and set of measured qubits - measure_sampler(circ.ops.begin() + first_meas, circ.ops.end(), shots, state, result, rng); -} - -template -void Controller::run_circuit_without_sampled_noise(Circuit &circ, - const Noise::NoiseModel &noise, - const json_t &config, - const Method method, - ExperimentResult &result) const -{ - State_t state; - - // Validate gateset and memory requirements, raise exception if they're exceeded - validate_state(state, circ, noise, true); - - // Set state config - state.set_config(config); - state.set_parallelization(parallel_state_update_); - state.set_global_phase(circ.global_phase_angle); - - bool can_sample = circ.can_sample; - - // Optimize circuit - Noise::NoiseModel dummy_noise; - - auto fusion_pass = transpile_fusion(method, circ.opset(), config); - fusion_pass.optimize_circuit(circ, dummy_noise, state.opset(), result); - - // Cache blocking pass - uint_t block_bits = circ.num_qubits; - if(state.multi_chunk_distribution_supported()){ - auto cache_block_pass = transpile_cache_blocking(method, circ, dummy_noise, config); - cache_block_pass.set_sample_measure(can_sample); - cache_block_pass.optimize_circuit(circ, dummy_noise, state.opset(), result); - if (cache_block_pass.enabled()) { - block_bits = cache_block_pass.block_bits(); - } - } - // Check if measure sampling supported - can_sample &= check_measure_sampling_opt(circ, method); - auto max_bits = get_max_matrix_qubits(circ); - - // Check if measure sampler and optimization are valid - if (can_sample) { - // Implement measure sampler - if (parallel_shots_ <= 1) { - state.set_distribution(num_process_per_experiment_); - state.set_max_matrix_qubits(max_bits); - RngEngine rng; - rng.set_seed(circ.seed); - run_with_sampling(circ, state, result, rng, block_bits, circ.shots); - } else { - // Vector to store parallel thread output data - std::vector par_results(parallel_shots_); - -#pragma omp parallel for num_threads(parallel_shots_) - for (int i = 0; i < parallel_shots_; i++) { - uint_t i_shot = circ.shots*i/parallel_shots_; - uint_t shot_end = circ.shots*(i+1)/parallel_shots_; - uint_t this_shot = shot_end - i_shot; - - State_t shot_state; - // Set state config - shot_state.set_config(config); - shot_state.set_parallelization(parallel_state_update_); - shot_state.set_global_phase(circ.global_phase_angle); - - shot_state.set_max_matrix_qubits(max_bits); - - RngEngine rng; - rng.set_seed(circ.seed + i); - - run_with_sampling(circ, shot_state, par_results[i], rng, block_bits, this_shot); - - shot_state.add_metadata(par_results[i]); - } - for (auto &res : par_results) { - result.combine(std::move(res)); - } - - if (sim_device_name_ == "GPU"){ - if(parallel_shots_ >= num_gpus_) - result.metadata.add(num_gpus_, "gpu_parallel_shots_"); - else - result.metadata.add(parallel_shots_, "gpu_parallel_shots_"); - } - } - // Add measure sampling metadata - result.metadata.add(true, "measure_sampling"); - - } - else{ - // Perform standard execution if we cannot apply the - // measurement sampling optimization - - if(block_bits == circ.num_qubits && enable_batch_multi_shots_ && state.multi_shot_parallelization_supported()){ - //apply batched multi-shots optimization (currenly only on GPU) - state.set_max_bached_shots(max_batched_states_); - state.set_distribution(num_processes_); - state.set_max_matrix_qubits(max_bits); - state.allocate(circ.num_qubits, circ.num_qubits, circ.shots); //allocate multiple-shots - - //qreg is initialized inside state class - state.initialize_creg(circ.num_memory, circ.num_registers); - - state.apply_ops_multi_shots(circ.ops.cbegin(), circ.ops.cend(), noise, result, circ.seed, true); - - state.save_count_data(result,save_creg_memory_); - - // Add batched multi-shots optimizaiton metadata - result.metadata.add(true, "batched_shots_optimization"); - } - else{ - std::vector par_results(parallel_shots_); - int_t par_shots = parallel_shots_; - if(block_bits != circ.num_qubits) - par_shots = 1; - - auto run_circuit_without_sampled_noise_lambda = [this,&par_results,circ,noise,config,method,block_bits,max_bits,par_shots](int_t i){ - uint_t i_shot,shot_end; - i_shot = circ.shots*i/par_shots; - shot_end = circ.shots*(i+1)/par_shots; - - State_t par_state; - // Set state config - par_state.set_config(config); - par_state.set_parallelization(parallel_state_update_); - par_state.set_global_phase(circ.global_phase_angle); - - par_state.set_distribution(num_process_per_experiment_); - par_state.set_max_matrix_qubits(max_bits ); - - // allocate qubit register - par_state.allocate(circ.num_qubits, block_bits); - - for(;i_shot 1),0,par_shots,run_circuit_without_sampled_noise_lambda); - - for (auto &res : par_results) { - result.combine(std::move(res)); - } - if (sim_device_name_ == "GPU"){ - if(par_shots >= num_gpus_) - result.metadata.add(num_gpus_, "gpu_parallel_shots_"); - else - result.metadata.add(par_shots, "gpu_parallel_shots_"); - } - } - } - state.add_metadata(result); -} - -template -void Controller::run_circuit_with_sampled_noise( - const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, - const Method method, ExperimentResult &result) const -{ - std::vector par_results(parallel_shots_); - - auto run_circuit_with_sampled_noise_lambda = [this,&par_results,circ,noise,config,method](int_t i){ - State_t state; - uint_t i_shot,shot_end; - Noise::NoiseModel dummy_noise; - - // Validate gateset and memory requirements, raise exception if they're exceeded - validate_state(state, circ, noise, true); - - // Set state config - state.set_config(config); - state.set_parallelization(parallel_state_update_); - state.set_global_phase(circ.global_phase_angle); - - // Transpilation for circuit noise method - auto fusion_pass = transpile_fusion(method, circ.opset(), config); - auto cache_block_pass = transpile_cache_blocking(method, circ, noise, config); - - i_shot = circ.shots*i/parallel_shots_; - shot_end = circ.shots*(i+1)/parallel_shots_; - - for(;i_shot 1),0,parallel_shots_,run_circuit_with_sampled_noise_lambda); - - for (auto &res : par_results) { - result.combine(std::move(res)); - } - - if (sim_device_name_ == "GPU"){ - if(parallel_shots_ >= num_gpus_) - result.metadata.add(num_gpus_, "gpu_parallel_shots_"); - else - result.metadata.add(parallel_shots_, "gpu_parallel_shots_"); - } -} - -//------------------------------------------------------------------------- -// Measure sampling optimization -//------------------------------------------------------------------------- - -bool Controller::check_measure_sampling_opt(const Circuit &circ, - const Method method) const { - // Check if circuit has sampling flag disabled - if (circ.can_sample == false) { - return false; - } - - // If density matrix, unitary, superop method all supported instructions - // allow sampling - if (method == Method::density_matrix || - method == Method::superop || - method == Method::unitary) { - return true; - } - - // If circuit contains a non-initial initialize that is not a full width - // instruction we can't sample - if (circ.can_sample_initialize == false) { - return false; - } - - // Check if non-density matrix simulation and circuit contains - // a stochastic instruction before measurement - // ie. reset, kraus, superop - // TODO: - // * Resets should be allowed if applied to |0> state (no gates before). - if (circ.opset().contains(Operations::OpType::reset) || - circ.opset().contains(Operations::OpType::kraus) || - circ.opset().contains(Operations::OpType::superop) || - circ.opset().contains(Operations::OpType::jump) || - circ.opset().contains(Operations::OpType::mark )) { - return false; - } - // Otherwise true - return true; -} - -template -void Controller::measure_sampler( - InputIterator first_meas, InputIterator last_meas, uint_t shots, - State_t &state, ExperimentResult &result, RngEngine &rng, int_t shot_index) const -{ - // Check if meas_circ is empty, and if so return initial creg - if (first_meas == last_meas) { - while (shots-- > 0) { - save_count_data(result, state.creg()); - } - return; - } - - std::vector meas_ops; - std::vector roerror_ops; - for (auto op = first_meas; op != last_meas; op++) { - if (op->type == Operations::OpType::roerror) { - roerror_ops.push_back(*op); - } else { /*(op.type == Operations::OpType::measure) */ - meas_ops.push_back(*op); - } - } - - // Get measured qubits from circuit sort and delete duplicates - std::vector meas_qubits; // measured qubits - for (const auto &op : meas_ops) { - for (size_t j = 0; j < op.qubits.size(); ++j) - meas_qubits.push_back(op.qubits[j]); - } - sort(meas_qubits.begin(), meas_qubits.end()); - meas_qubits.erase(unique(meas_qubits.begin(), meas_qubits.end()), - meas_qubits.end()); - - // Generate the samples - uint_t shots_or_index; - if(shot_index < 0) - shots_or_index = shots; - else - shots_or_index = shot_index; - - auto timer_start = myclock_t::now(); - auto all_samples = state.sample_measure(meas_qubits, shots_or_index, rng); - auto time_taken = - std::chrono::duration(myclock_t::now() - timer_start).count(); - result.metadata.add(time_taken, "sample_measure_time"); - - // Make qubit map of position in vector of measured qubits - std::unordered_map qubit_map; - for (uint_t j = 0; j < meas_qubits.size(); ++j) { - qubit_map[meas_qubits[j]] = j; - } - - // Maps of memory and register to qubit position - std::map memory_map; - std::map register_map; - for (const auto &op : meas_ops) { - for (size_t j = 0; j < op.qubits.size(); ++j) { - auto pos = qubit_map[op.qubits[j]]; - if (!op.memory.empty()) - memory_map[op.memory[j]] = pos; - if (!op.registers.empty()) - register_map[op.registers[j]] = pos; - } - } - - // Process samples - uint_t num_memory = (memory_map.empty()) ? 0ULL : 1 + memory_map.rbegin()->first; - uint_t num_registers = (register_map.empty()) ? 0ULL : 1 + register_map.rbegin()->first; - ClassicalRegister creg; - while (!all_samples.empty()) { - auto sample = all_samples.back(); - creg.initialize(num_memory, num_registers); - - // process memory bit measurements - for (const auto &pair : memory_map) { - creg.store_measure(reg_t({sample[pair.second]}), reg_t({pair.first}), - reg_t()); - } - // process register bit measurements - for (const auto &pair : register_map) { - creg.store_measure(reg_t({sample[pair.second]}), reg_t(), - reg_t({pair.first})); - } - - // process read out errors for memory and registers - for (const Operations::Op &roerror : roerror_ops) { - creg.apply_roerror(roerror, rng); - } - - // Save count data - save_count_data(result, creg); - - // pop off processed sample - all_samples.pop_back(); - } -} - - -//------------------------------------------------------------------------- -// Validation -//------------------------------------------------------------------------- - -std::vector -Controller::simulation_methods(std::vector &circuits, - Noise::NoiseModel &noise_model) const { - // Does noise model contain kraus noise - bool kraus_noise = (noise_model.opset().contains(Operations::OpType::kraus) || - noise_model.opset().contains(Operations::OpType::superop)); - - if (method_ == Method::automatic) { - // Determine simulation methods for each circuit and noise model - std::vector sim_methods; - bool superop_enabled = false; - bool kraus_enabled = false; - for (const auto& circ: circuits) { - auto method = automatic_simulation_method(circ, noise_model); - sim_methods.push_back(method); - if (!superop_enabled && (method == Method::density_matrix || method == Method::superop)) { - noise_model.enable_superop_method(max_parallel_threads_); - superop_enabled = true; - } else if (kraus_noise && !kraus_enabled && - (method == Method::statevector || method == Method::matrix_product_state)) { - noise_model.enable_kraus_method(max_parallel_threads_); - kraus_enabled = true; - } - } - return sim_methods; - } - - // Use non-automatic default method for all circuits - std::vector sim_methods(circuits.size(), method_); - if (method_ == Method::density_matrix || method_ == Method::superop) { - noise_model.enable_superop_method(max_parallel_threads_); - } else if (kraus_noise && ( - method_ == Method::statevector - || method_ == Method::matrix_product_state)) { - noise_model.enable_kraus_method(max_parallel_threads_); - } - return sim_methods; -} - -Controller::Method -Controller::automatic_simulation_method(const Circuit &circ, - const Noise::NoiseModel &noise_model) const { - // If circuit and noise model are Clifford run on Stabilizer simulator - if (validate_method(Method::stabilizer, circ, noise_model, false)) { - return Method::stabilizer; - } - // For noisy simulations we enable the density matrix method if - // shots > 2 ** num_qubits. This is based on a rough estimate that - // a single shot of the density matrix simulator is approx 2 ** nq - // times slower than a single shot of statevector due the increased - // dimension - if (noise_model.has_quantum_errors() && circ.num_qubits < 64 && - circ.shots > (1ULL << circ.num_qubits) && - validate_method(Method::density_matrix, circ, noise_model, false) && - check_measure_sampling_opt(circ, Method::density_matrix)) { - return Method::density_matrix; - } - - // If the special conditions for stabilizer or density matrix are - // not satisfied we choose simulation method based on supported - // operations only with preference given by memory requirements - // statevector > density matrix > matrix product state > unitary > superop - // typically any save state instructions will decide the method. - const std::vector methods({Method::statevector, - Method::density_matrix, - Method::matrix_product_state, - Method::unitary, - Method::superop}); - for (const auto& method : methods) { - if (validate_method(method, circ, noise_model, false)) - return method; - } - - // If we got here, circuit isn't compatible with any of the simulation - // method so fallback to a default method of statevector. The execution will - // fail but we will get partial result generation and generate a user facing - // error message - return Method::statevector; -} - -bool Controller::validate_method(Method method, - const Circuit &circ, - const Noise::NoiseModel &noise_model, - bool throw_except) const { - // Switch wrapper for templated function validate_state - switch (method) { - case Method::stabilizer: - return validate_state(Stabilizer::State(), circ, noise_model, throw_except); - case Method::extended_stabilizer: - return validate_state(ExtendedStabilizer::State(), circ, noise_model, throw_except); - case Method::matrix_product_state: - return validate_state(MatrixProductState::State(), circ, noise_model, throw_except); - case Method::statevector: - return validate_state(Statevector::State<>(), circ, noise_model, throw_except); - case Method::density_matrix: - return validate_state(DensityMatrix::State<>(), circ, noise_model, throw_except); - case Method::unitary: - return validate_state(QubitUnitary::State<>(), circ, noise_model, throw_except); - case Method::superop: - return validate_state(QubitSuperoperator::State<>(), circ, noise_model, throw_except); - case Method::automatic: - throw std::runtime_error("Cannot validate circuit for unresolved simulation method."); - } -} - - -template -bool Controller::validate_state(const state_t &state, const Circuit &circ, - const Noise::NoiseModel &noise, - bool throw_except) const { - std::stringstream error_msg; - std::string circ_name; - JSON::get_value(circ_name, "name", circ.header); - - // Check if a circuit is valid for state ops - bool circ_valid = state.opset().contains(circ.opset()); - if (throw_except && !circ_valid) { - error_msg << "Circuit " << circ_name << " contains invalid instructions "; - error_msg << state.opset().difference(circ.opset()); - error_msg << " for \"" << state.name() << "\" method."; - } - - // Check if a noise model valid for state ops - bool noise_valid = noise.is_ideal() || state.opset().contains(noise.opset()); - if (throw_except && !noise_valid) { - error_msg << "Noise model contains invalid instructions "; - error_msg << state.opset().difference(noise.opset()); - error_msg << " for \"" << state.name() << "\" method."; - } - - // Validate memory requirements - bool memory_valid = true; - if (max_memory_mb_ > 0) { - size_t required_mb = state.required_memory_mb(circ.num_qubits, circ.ops) / num_process_per_experiment_; - size_t mem_size = (sim_device_ == Device::GPU) ? max_memory_mb_ + max_gpu_memory_mb_ : max_memory_mb_; - memory_valid = (required_mb <= mem_size); - if (throw_except && !memory_valid) { - error_msg << "Insufficient memory to run circuit " << circ_name; - error_msg << " using the " << state.name() << " simulator."; - error_msg << " Required memory: " << required_mb << "M, max memory: " << max_memory_mb_ << "M"; - if (sim_device_ == Device::GPU) { - error_msg << " (Host) + " << max_gpu_memory_mb_ << "M (GPU)"; - } - } - } - - if (noise_valid && circ_valid && memory_valid) { - return true; - } - - // One of the validation checks failed for the current state - if (throw_except) { - throw std::runtime_error(error_msg.str()); - } - return false; -} - -void Controller::save_exception_to_results(Result &result, - const std::exception &e) const { - result.status = Result::Status::error; - result.message = e.what(); - for (auto &res : result.results) { - res.status = ExperimentResult::Status::error; - res.message = e.what(); - } -} - -int_t Controller::get_matrix_bits(const Operations::Op& op) const -{ - int_t bit = 1; - if(op.type == Operations::OpType::matrix || op.type == Operations::OpType::diagonal_matrix || op.type == Operations::OpType::initialize) - bit = op.qubits.size(); - else if(op.type == Operations::OpType::kraus || op.type == Operations::OpType::superop){ - if(method_ == Method::density_matrix) - bit = op.qubits.size() * 2; - else - bit = op.qubits.size(); - } - return bit; -} - -int_t Controller::get_max_matrix_qubits(const Circuit &circ) const -{ - int_t max_bits = 0; - int_t i; - - for(i=0;i -#include "misc/hacks.hpp" -#include "framework/results/result.hpp" - -//========================================================================= -// Controller Execute interface -//========================================================================= - -namespace AER { - -template -Result controller_execute(const inputdata_t& qobj) { - controller_t controller; - - // Fix for MacOS and OpenMP library double initialization crash. - // Issue: https://github.com/Qiskit/qiskit-aer/issues/1 - if (Parser::check_key("config", qobj)) { - std::string path; - const auto& config = Parser::get_value("config", qobj); - Parser::get_value(path, "library_dir", config); - Hacks::maybe_load_openmp(path); - } - return controller.execute(qobj); -} - - -} // end namespace AER -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/avx2_detect.hpp b/quantum/plugins/ibm/aer/src/framework/avx2_detect.hpp deleted file mode 100644 index 49f5d7395..000000000 --- a/quantum/plugins/ibm/aer/src/framework/avx2_detect.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_controller_avx2_detect_hpp_ -#define _aer_controller_avx2_detect_hpp_ - -#include -#include -#include - -#include "misc/common_macros.hpp" -#if defined(_MSC_VER) - #include -#elif defined(GNUC_AVX2) - #include -#endif - - -namespace { -inline void ccpuid(int cpu_info[4], int function_id){ -#if defined(_MSC_VER) - __cpuid(cpu_info, function_id); -#elif defined(GNUC_AVX2) - __cpuid(function_id, - cpu_info[0], - cpu_info[1], - cpu_info[2], - cpu_info[3]); -#else // We don't support this platform intrinsics - cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; -#endif -} - -inline void cpuidex(int cpu_info[4], int function_id, int subfunction_id){ -#if defined(_MSC_VER) - __cpuidex(cpu_info, function_id, subfunction_id); -#elif defined(GNUC_AVX2) - __cpuid_count(function_id, subfunction_id, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); -#else // We don't support this platform intrinsics - cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; -#endif -} -} - -namespace AER { - -inline bool is_avx2_supported(){ -#if defined(GNUC_AVX2) || defined(_MSC_VER) - static bool cached = false; - static bool is_supported = false; - if(cached) - return is_supported; - - std::array cpui; - ccpuid(cpui.data(), 0); - auto num_ids = cpui[0]; - if(num_ids < 7){ - cached = true; - is_supported = false; - return false; - } - - std::vector> data; - for (int i = 0; i <= num_ids; ++i){ - cpuidex(cpui.data(), i, 0); - data.push_back(cpui); - } - - std::bitset<32> f_1_ECX = data[1][2]; - std::bitset<32> f_7_EBX = data[7][1]; - - bool is_fma_supported = (f_1_ECX[12] & 1); - bool is_avx2_supported = (f_7_EBX[5] & 1); - - cached = true; - is_supported = is_fma_supported && is_avx2_supported; - return is_supported; -#else - return false; -#endif -} -// end namespace AER -} -#endif - - diff --git a/quantum/plugins/ibm/aer/src/framework/blas_protos.hpp b/quantum/plugins/ibm/aer/src/framework/blas_protos.hpp deleted file mode 100755 index d2803c66e..000000000 --- a/quantum/plugins/ibm/aer/src/framework/blas_protos.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019, 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -// Dependencies: BLAS -// These are the declarations for the various high-performance matrix routines -// used by the matrix class. An openblas install is required. - -#ifndef _aer_framework_blas_protos_hpp -#define _aer_framework_blas_protos_hpp - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//=========================================================================== -// Prototypes for level 3 BLAS -//=========================================================================== - -// Single-Precison Real Matrix-Vector Multiplcation -void sgemv_(const char *TransA, const size_t *M, const size_t *N, - const float *alpha, const float *A, const size_t *lda, - const float *x, const size_t *incx, const float *beta, float *y, - const size_t *lincy); -// Double-Precison Real Matrix-Vector Multiplcation -void dgemv_(const char *TransA, const size_t *M, const size_t *N, - const double *alpha, const double *A, const size_t *lda, - const double *x, const size_t *incx, const double *beta, double *y, - const size_t *lincy); -// Single-Precison Complex Matrix-Vector Multiplcation -void cgemv_(const char *TransA, const size_t *M, const size_t *N, - const std::complex *alpha, const std::complex *A, - const size_t *lda, const std::complex *x, const size_t *incx, - const std::complex *beta, std::complex *y, - const size_t *lincy); -// Double-Precison Real Matrix-Vector Multiplcation -void zgemv_(const char *TransA, const size_t *M, const size_t *N, - const std::complex *alpha, const std::complex *A, - const size_t *lda, const std::complex *x, - const size_t *incx, const std::complex *beta, - std::complex *y, const size_t *lincy); -// Single-Precison Real Matrix-Matrix Multiplcation -void sgemm_(const char *TransA, const char *TransB, const size_t *M, - const size_t *N, const size_t *K, const float *alpha, - const float *A, const size_t *lda, const float *B, - const size_t *lba, const float *beta, float *C, size_t *ldc); -// Double-Precison Real Matrix-Matrix Multiplcation -void dgemm_(const char *TransA, const char *TransB, const size_t *M, - const size_t *N, const size_t *K, const double *alpha, - const double *A, const size_t *lda, const double *B, - const size_t *lba, const double *beta, double *C, size_t *ldc); -// Single-Precison Complex Matrix-Matrix Multiplcation -void cgemm_(const char *TransA, const char *TransB, const size_t *M, - const size_t *N, const size_t *K, const std::complex *alpha, - const std::complex *A, const size_t *lda, - const std::complex *B, const size_t *ldb, - const std::complex *beta, std::complex *C, - size_t *ldc); -// Double-Precison Complex Matrix-Matrix Multiplcation -void zgemm_(const char *TransA, const char *TransB, const size_t *M, - const size_t *N, const size_t *K, const std::complex *alpha, - const std::complex *A, const size_t *lda, - const std::complex *B, const size_t *ldb, - const std::complex *beta, std::complex *C, - size_t *ldc); - -// Reduces a Single-Precison Complex Hermitian matrix A to real symmetric tridiagonal form -void chetrd_(char *TRANS, int *N, std::complex *A, - int *LDA, float *d, float *e, std::complex *tau, - std::complex *work, int *lwork, int *info); - -// Reduces a Double-Precison Complex Hermitian matrix A to real symmetric tridiagonal form T -void zhetrd_(char *TRANS, int *N, std::complex *A, - int *LDA, double *d, double *e, std::complex *tau, - std::complex *work, int *lwork, int *info); - -// Computes all eigenvalues and, optionally, eigenvectors of a -// Single-Precison Complex symmetric positive definite tridiagonal matrix -void cpteqr_(char* compz, int *n, float *d, float *e, - std::complex *z, int* ldz, - std::complex *work, int *info); - -// Computes all eigenvalues and, optionally, eigenvectors of a -// Double-Precison Complex symmetric positive definite tridiagonal matrix -void zpteqr_(char* compz, int *n, double *d, double *e, - std::complex *z, int* ldz, - std::complex *work, int *info); - -// Computes selected eigenvalues and, optionally, eigenvectors -// of a Single-Precison Complex Hermitian matrix A -void cheevx_(char *jobz, char *range, char *uplo, int *n, - std::complex *a, int *lda, float *vl, - float *vu, int *il, int *iu, float *abstol, - int *m, float *w, std::complex *z, int *ldz, - std::complex *work, int *lwork, float *rwork, - int *iwork, int *ifail, int *info); - -// Computes selected eigenvalues and, optionally, eigenvectors -// of a Double-Precison Complex Hermitian matrix A -void zheevx_(char *jobz, char *range, char *uplo, int *n, - std::complex *a, int *lda, double *vl, - double *vu, int *il, int *iu, double *abstol, - int *m, double *w, std::complex *z, int *ldz, - std::complex *work, int *lwork, double *rwork, - int *iwork, int *ifail, int *info); - -// Determines Single-Precision machine parameters. -float slamch_(char *cmach); - -// Determines Double-Precision machine parameters. -double dlamch_(char *cmach); - -#ifdef __cplusplus -} -#endif - -namespace AerBlas { - -std::array Trans = {'N', 'T', 'C'}; -/* Trans (input) CHARACTER*1. - On entry, TRANSA specifies the form of op( A ) to be used in the - matrix multiplication as follows: - = 'N' no transpose; - = 'T' transpose of A; - = 'C' hermitian conjugate of A. -*/ -std::array UpLo = {'U', 'L'}; -/* UpLo (input) CHARACTER*1 - = 'U': Upper triangle of A is stored; - = 'L': Lower triangle of A is stored. -*/ -std::array Jobz = {'V', 'N'}; -/* Jobz (input) CHARACTER*1 - = 'N': Compute eigenvalues only; - = 'V': Compute eigenvalues and eigenvectors. -*/ -std::array Range = {'A', 'V', 'I'}; -/* Range (input) CHARACTER*1 - = 'A': all eigenvalues will be found. - = 'V': all eigenvalues in the half-open interval - (VL,VU] will be found. - = 'I': the IL-th through IU-th eigenvalues will - be found. -*/ - -} // namespace AerBlas - -#endif // end _blas_protos_h_ diff --git a/quantum/plugins/ibm/aer/src/framework/circuit.hpp b/quantum/plugins/ibm/aer/src/framework/circuit.hpp deleted file mode 100755 index af6148c3a..000000000 --- a/quantum/plugins/ibm/aer/src/framework/circuit.hpp +++ /dev/null @@ -1,518 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_circuit_hpp_ -#define _aer_framework_circuit_hpp_ - -#include - -#include "framework/operations.hpp" -#include "framework/opset.hpp" - -namespace AER { - -//============================================================================ -// Circuit class for Qiskit-Aer -//============================================================================ - -// A circuit is a list of Ops along with a specification of maximum needed -// qubits, memory bits, and register bits for the input operators. -class Circuit { -public: - using Op = Operations::Op; - using OpType = Operations::OpType; - - // Circuit operations - std::vector ops; - - // Circuit parameters updated by from ops by set_params - uint_t num_qubits = 0; // maximum number of qubits needed for ops - uint_t num_memory = 0; // maximum number of memory clbits needed for ops - uint_t num_registers = 0; // maximum number of registers clbits needed for ops - - // Measurement params - bool has_conditional = false; // True if any ops are conditional - bool can_sample = true; // True if circuit tail contains measure, roerror, barrier. - size_t first_measure_pos = 0; // Position of first measure instruction - bool can_sample_initialize = true; // True if circuit contains at most 1 initialize - // and it is the first instruction in the circuit - - // Circuit metadata constructed from json QobjExperiment - uint_t shots = 1; - uint_t seed; - json_t header; - double global_phase_angle = 0; - bool remapped_qubits = false; // True if qubits have been remapped - - // Constructor - // The constructor automatically calculates the num_qubits, num_memory, num_registers - // parameters by scanning the input list of ops. - Circuit() {set_random_seed();} - Circuit(const std::vector &_ops, bool truncation = false); - Circuit(std::vector &&_ops, bool truncation = false); - - // Construct a circuit from JSON - template - Circuit(const inputdata_t& circ, bool truncation = false); - - template - Circuit(const inputdata_t& circ, const json_t& qobj_config, bool truncation = false); - - //----------------------------------------------------------------------- - // Set containers - //----------------------------------------------------------------------- - - // Return the opset for the circuit - inline const auto& opset() const {return opset_;} - - // Return the used qubits for the circuit - inline const auto& qubits() const {return qubitset_;} - - // Return the used memory for the circuit - inline const auto& memory() const {return memoryset_;} - - // Return the used registers for the circuit - inline const auto& registers() const {return registerset_;} - - // Return the mapping of input op qubits to circuit qubits - inline const auto& qubit_map() const {return qubitmap_;} - - //----------------------------------------------------------------------- - // Utility methods - //----------------------------------------------------------------------- - - // Automatically set the number of qubits, memory, registers, and check - // for conditionals and measure sampling based on ops. - // If `truncation = true` also perform truncation of - // unnecessary qubits, remapping of remaining qubits, checking - // of measure sampling optimization, and delay of measurements - // to end of circuit - void set_params(bool truncation = false); - - // Set the circuit rng seed to random value - inline void set_random_seed() {seed = std::random_device()();} - -private: - Operations::OpSet opset_; // Set of operation types contained in circuit - std::set qubitset_; // Set of qubits used in the circuit - std::set memoryset_; // Set of memory bits used in the circuit - std::set registerset_; // Set of register bits used in the circuit - std::set saveset_; // Set of key names for save data instructions - - // Mapping from loaded op qubits to remapped truncated circuit qubits - std::unordered_map qubitmap_; - - // Add type, qubit, memory, conditional metadata information from op - void add_op_metadata(const Op& op); - - // Reset circuit metadata - void reset_metadata(); - - // Helper function for optimized set params - bool check_result_ancestor(const Op& op, - std::unordered_set& ancestor_qubits) const; - - // Helper function for optimized set params - void remap_qubits(Op& op) const; -}; - - -// Json conversion function -inline void from_json(const json_t& js, Circuit &circ) {circ = Circuit(js);} - - -//============================================================================ -// Implementation: Circuit methods -//============================================================================ - -Circuit::Circuit(const std::vector &_ops, bool truncation) : Circuit() { - ops = _ops; - set_params(truncation); -} - -Circuit::Circuit(std::vector &&_ops, bool truncation) : Circuit() { - ops = std::move(_ops); - set_params(truncation); -} - -template -Circuit::Circuit(const inputdata_t &circ, bool truncation) : Circuit(circ, json_t(), truncation) {} - -template -Circuit::Circuit(const inputdata_t &circ, const json_t &qobj_config, bool truncation) : Circuit() { - // Get config - json_t config = qobj_config; - if (Parser::check_key("config", circ)) { - json_t circ_config; - Parser::get_value(circ_config, "config", circ); - for (auto it = circ_config.cbegin(); it != circ_config.cend(); ++it) { - config[it.key()] = it.value(); // overwrite circuit level config values - } - } - - // Load metadata - Parser::get_value(header, "header", circ); - Parser::get_value(shots, "shots", config); - Parser::get_value(global_phase_angle, "global_phase", header); - - // Load instructions - if (Parser::check_key("instructions", circ) == false) { - throw std::invalid_argument("Invalid Qobj experiment: no \"instructions\" field."); - } - const auto input_ops = Parser::get_list("instructions", circ); - - // Convert to Ops - // TODO: If parser could support reverse iteration through the list of ops without - // conversion we could call `get_reversed_ops` on the inputdata without first - // converting. - std::vector converted_ops; - for(auto the_op: input_ops){ - converted_ops.emplace_back(Operations::input_to_op(the_op)); - } - ops = std::move(converted_ops); - set_params(truncation); - - // Check for specified memory slots - uint_t memory_slots = 0; - Parser::get_value(memory_slots, "memory_slots", config); - if (memory_slots < num_memory) { - throw std::invalid_argument("Invalid Qobj experiment: not enough memory slots."); - } - // override memory slot number - num_memory = memory_slots; - - // Check for specified n_qubits - if (Parser::check_key("n_qubits", config)) { - // uint_t n_qubits = config["n_qubits"]; - uint_t n_qubits; - Parser::get_value(n_qubits, "n_qubits", config); - if (n_qubits < num_qubits) { - throw std::invalid_argument("Invalid Qobj experiment: n_qubits < instruction qubits."); - } - if (!truncation) { - // Override minimal circuit qubit number with qobj number if truncation - // is explicitly disabled. - num_qubits = n_qubits; - } - } -} - -//------------------------------------------------------------------------- -// Circuit initialization optimization -//------------------------------------------------------------------------- - -void Circuit::reset_metadata() { - - opset_ = Operations::OpSet(); - qubitset_.clear(); - memoryset_.clear(); - registerset_.clear(); - saveset_.clear(); - qubitmap_.clear(); - - num_qubits = 0; - num_memory = 0; - num_registers = 0; - - has_conditional = false; - can_sample = true; - first_measure_pos = 0; - can_sample_initialize = true; -} - -void Circuit::add_op_metadata(const Op& op) { - has_conditional |= op.conditional; - opset_.insert(op); - qubitset_.insert(op.qubits.begin(), op.qubits.end()); - memoryset_.insert(op.memory.begin(), op.memory.end()); - registerset_.insert(op.registers.begin(), op.registers.end()); - - // Check for duplicate save keys - if (Operations::SAVE_TYPES.find(op.type) != Operations::SAVE_TYPES.end()) { - auto pair = saveset_.insert(op.string_params[0]); - if (!pair.second) { - throw std::invalid_argument("Duplicate key \"" + op.string_params[0] + - "\" in save instruction."); - } - } -} - - -void Circuit::set_params(bool truncation) { - // Clear current circuit metadata - reset_metadata(); - if (ops.empty()) return; - - // Analyze input ops from tail to head to get locations of ancestor, - // first measurement position and last initialize position - const auto size = ops.size(); - std::vector ancestor(size, false); - first_measure_pos = size; - bool has_measure = false; - size_t num_ancestors = 0; - size_t last_ancestor_pos = 0; - size_t last_initialize_pos = 0; - bool ops_to_remove = false; - - std::unordered_set ancestor_qubits; - for (size_t i = 0; i < size; ++ i) { - const size_t rpos = size - i - 1; - const auto& op = ops[rpos]; - if (!truncation || check_result_ancestor(op, ancestor_qubits)) { - add_op_metadata(op); - ancestor[rpos] = true; - num_ancestors++; - if (op.type == OpType::measure) { - first_measure_pos = rpos; - has_measure = true; - } else if (op.type == OpType::initialize && last_initialize_pos == 0) { - last_initialize_pos = rpos; - } - if (last_ancestor_pos == 0) { - last_ancestor_pos = rpos; - } - } else if (truncation && !ops_to_remove){ - ops_to_remove = true; - } - } - - // Set qubit size and check for truncaiton - remapped_qubits = false; - if (truncation) { - // Generate mapping of original qubits to ancestor set - uint_t idx = 0; - for (const auto& qubit: qubitset_) { - if (!remapped_qubits && idx != qubit) { - // qubits will be remapped - remapped_qubits = true; - } - qubitmap_[qubit] = idx; - idx++; - } - } - - // Set qubit and memory size - num_memory = (memoryset_.empty()) ? 0 : 1 + *memoryset_.rbegin(); - num_registers = (registerset_.empty()) ? 0 : 1 + *registerset_.rbegin(); - if (remapped_qubits) { - num_qubits = qubitset_.size(); - } else { - num_qubits = (qubitset_.empty()) ? 0 : 1 + *qubitset_.rbegin(); - } - - // Check if can sample initialize - if (last_initialize_pos > 0 && - ops[last_initialize_pos].qubits.size() < num_qubits) { - can_sample_initialize = false; - can_sample = false; - } - - // Check measurement opt and split tail meas and non-meas ops - std::vector tail_pos; - std::vector tail_meas_ops; - if (has_measure && can_sample) { - std::unordered_set meas_qubits; - std::unordered_set modified_qubits; - - for (uint_t pos = first_measure_pos; pos <= last_ancestor_pos; ++pos) { - if (ops_to_remove && !ancestor[pos]) { - // Skip if not ancestor - continue; - } - - const auto& op = ops[pos]; - if (op.conditional) { - can_sample = false; - break; - } - - switch (op.type) { - case OpType::measure: - case OpType::roerror: { - meas_qubits.insert(op.qubits.begin(), op.qubits.end()); - tail_meas_ops.push_back(op); - break; - } - case OpType::snapshot: - case OpType::save_state: - case OpType::save_expval: - case OpType::save_expval_var: - case OpType::save_statevec: - case OpType::save_statevec_dict: - case OpType::save_densmat: - case OpType::save_probs: - case OpType::save_probs_ket: - case OpType::save_amps: - case OpType::save_amps_sq: - case OpType::save_stabilizer: - case OpType::save_clifford: - case OpType::save_unitary: - case OpType::save_mps: - case OpType::save_superop: - { - can_sample = false; - break; - } - default: { - for (const auto &qubit : op.qubits) { - if (meas_qubits.find(qubit) != meas_qubits.end()) { - can_sample = false; - break; - } - } - tail_pos.push_back(pos); - } - } - if (!can_sample) { - break; - } - } - } - - // Counter for current position in ops as we shuffle ops - size_t op_idx = 0; - size_t head_end = 0; - std::set marks; - std::set dests; - if (has_measure && can_sample) { - head_end = first_measure_pos; - } else if (num_ancestors > 0) { - head_end = last_ancestor_pos + 1; - } - for (size_t pos = 0; pos < head_end; ++pos) { - if (ops_to_remove && !ancestor[pos]) { - // Skip if not ancestor - continue; - } - if (remapped_qubits) { - remap_qubits(ops[pos]); - } - if (pos != op_idx) { - ops[op_idx] = std::move(ops[pos]); - } - if (ops[op_idx].type == OpType::jump) { - dests.insert(ops[op_idx].string_params[0]); - } else if (ops[op_idx].type == OpType::mark) { - auto& mark_name = ops[op_idx].string_params[0]; - if (marks.find(mark_name) != marks.end()) { - std::stringstream msg; - msg << "Duplicated mark destination:\"" << mark_name << "\"." << std::endl; - throw std::runtime_error(msg.str()); - } - marks.insert(mark_name); - } - if (pos == first_measure_pos) { - first_measure_pos = op_idx; - } - op_idx++; - } - - for (auto dest : dests) { - if (marks.find(dest) == marks.end()) { - std::stringstream msg; - msg << "Invalid jump destination:\"" << dest << "\"." << std::endl; - throw std::runtime_error(msg.str()); - } - } - - if (has_measure && can_sample) { - // Apply remapping to tail ops - for (size_t tidx = 0; tidx < tail_pos.size(); ++tidx) { - const auto tpos = tail_pos[tidx]; - if (!ops_to_remove && !ancestor[tpos]) { - continue; - } - auto& op = ops[tpos]; - if (remapped_qubits) { - remap_qubits(ops[tpos]); - } - if (tpos != op_idx) { - ops[op_idx] = std::move(op); - } - op_idx++; - } - // Now add remaining delayed measure ops - first_measure_pos = op_idx; - for (auto & op : tail_meas_ops) { - if (remapped_qubits) { - remap_qubits(op); - } - ops[op_idx] = std::move(op); - op_idx++; - } - } - // Handle edge case of truncation with no measurements - first_measure_pos = std::min(op_idx, first_measure_pos); - - // Resize to remove discarded ops - ops.resize(op_idx); -} - - -void Circuit::remap_qubits(Op& op) const { - reg_t new_qubits; - for (auto& qubit : op.qubits) { - new_qubits.push_back(qubitmap_.at(qubit)); - } - op.qubits = std::move(new_qubits); -} - - -bool Circuit::check_result_ancestor(const Op& op, std::unordered_set& ancestor_qubits) const { - switch (op.type) { - case OpType::barrier: - case OpType::nop: { - return false; - } - case OpType::bfunc: { - return true; - } - // Result generating types - case OpType::measure: - case OpType::roerror: - case OpType::snapshot: - case OpType::save_state: - case OpType::save_expval: - case OpType::save_expval_var: - case OpType::save_statevec: - case OpType::save_statevec_dict: - case OpType::save_densmat: - case OpType::save_probs: - case OpType::save_probs_ket: - case OpType::save_amps: - case OpType::save_amps_sq: - case OpType::save_stabilizer: - case OpType::save_clifford: - case OpType::save_unitary: - case OpType::save_mps: - case OpType::save_superop: { - ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); - return true; - } - default: { - for (const auto& qubit : op.qubits) { - if (ancestor_qubits.find(qubit) != ancestor_qubits.end()) { - ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); - return true; - } - } - return false; - } - } -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/creg.hpp b/quantum/plugins/ibm/aer/src/framework/creg.hpp deleted file mode 100755 index 2a79a0e87..000000000 --- a/quantum/plugins/ibm/aer/src/framework/creg.hpp +++ /dev/null @@ -1,256 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_creg_hpp_ -#define _aer_framework_creg_hpp_ - -#include "framework/operations.hpp" -#include "framework/utils.hpp" -#include "framework/rng.hpp" - -namespace AER { - -//============================================================================ -// ClassicalRegister base class for Qiskit-Aer -//============================================================================ - -// ClassicalRegister class -class ClassicalRegister { - -public: - - // Return the current value of the memory as little-endian hex-string - inline std::string memory_hex() const {return Utils::bin2hex(creg_memory_);} - - // Return the current value of the memory as little-endian bit-string - inline std::string memory_bin() const {return "0b" + creg_memory_;} - - // Return the current value of the memory as little-endian hex-string - inline std::string register_hex() const {return Utils::bin2hex(creg_register_);} - - // Return the current value of the memory as little-endian bit-string - inline std::string register_bin() const {return "0b" + creg_register_;} - - // Return the size of the memory bits - size_t memory_size() const {return creg_memory_.size();} - - // Return the size of the register bits - size_t register_size() const {return creg_register_.size();} - - // Return a reference to the current value of the memory - // this is a bit-string without the "0b" prefix. - inline auto& creg_memory() {return creg_memory_;} - - // Return a reference to the current value of the memory - // this is a bit-string without the "0b" prefix. - inline auto& creg_register() {return creg_register_;} - - // Initialize the memory and register bits to default values (all 0) - void initialize(size_t num_memory, size_t num_registers); - - // Initialize the memory and register bits to specific values - void initialize(size_t num_memory, - size_t num_registers, - const std::string &memory_hex, - const std::string ®ister_hex); - - // Return true if a conditional op test passes based on the current - // register bits values. - // If the op is not a conditional op this will return true. - bool check_conditional(const Operations::Op &op) const; - - // Apply a boolean function Op - void apply_bfunc(const Operations::Op &op); - - // Apply readout error instruction to classical registers - void apply_roerror(const Operations::Op &op, RngEngine &rng); - - // Store a measurement outcome in the specified memory and register bit locations - void store_measure(const reg_t &outcome, const reg_t &memory, const reg_t ®isters); - -protected: - - // Classical registers - std::string creg_memory_; // standard classical bit memory - std::string creg_register_; // optional classical bit register - - // Measurement config settings - bool return_hex_strings_ = true; // Set to false for bit-string output -}; - -//============================================================================ -// Implementations -//============================================================================ - -void ClassicalRegister::initialize(size_t num_memory, size_t num_register) { - // Set registers to the all 0 bit state - creg_memory_ = std::string(num_memory, '0'); - creg_register_ = std::string(num_register, '0'); -} - - -void ClassicalRegister::initialize(size_t num_memory, - size_t num_register, - const std::string &memory_hex, - const std::string ®ister_hex) { - // Convert to bit-string for internal storage - std::string memory_bin = Utils::hex2bin(memory_hex, false); - creg_memory_ = std::move(Utils::padleft_inplace(memory_bin, '0', num_memory)); - - std::string register_bin = Utils::hex2bin(register_hex, false); - creg_register_ = std::move(Utils::padleft_inplace(memory_bin, '0', num_register)); -} - - -void ClassicalRegister::store_measure(const reg_t &outcome, - const reg_t &memory, - const reg_t ®isters) { - // Assumes memory and registers are either empty or same size as outcome! - bool use_mem = !memory.empty(); - bool use_reg = !registers.empty(); - for (size_t j=0; j < outcome.size(); j++) { - if (use_mem) { - // least significant bit first ordering - const size_t pos = creg_memory_.size() - memory[j] - 1; - creg_memory_[pos] = std::to_string(outcome[j])[0]; // int->string->char - } - if (use_reg) { - // least significant bit first ordering - const size_t pos = creg_register_.size() - registers[j] - 1; - creg_register_[pos] = std::to_string(outcome[j])[0]; // int->string->char - } - } -} - - -bool ClassicalRegister::check_conditional(const Operations::Op &op) const { - // Check if op is conditional - if (op.conditional) - return (creg_register_[creg_register_.size() - op.conditional_reg - 1] == '1'); - - // Op is not conditional - return true; -} - - -void ClassicalRegister::apply_bfunc(const Operations::Op &op) { - - // Check input is boolean function op - if (op.type != Operations::OpType::bfunc) { - throw std::invalid_argument("ClassicalRegister::apply_bfunc: Input is not a bfunc op."); - } - - const std::string &mask = op.string_params[0]; - const std::string &target_val = op.string_params[1]; - int_t compared; // if equal this should be 0, if less than -1, if greater than +1 - - // Check if register size fits into a 64-bit integer - if (creg_register_.size() <= 64) { - uint_t reg_int = std::stoull(creg_register_, nullptr, 2); // stored as bitstring - uint_t mask_int = std::stoull(mask, nullptr, 16); // stored as hexstring - uint_t target_int = std::stoull(target_val, nullptr, 16); // stored as hexstring - compared = (reg_int & mask_int) - target_int; - } else { - // We need to use big ints so we implement the bit-mask via the binary string - // representation rather than using a big integer class - std::string mask_bin = Utils::hex2bin(mask, false); - size_t length = std::min(mask_bin.size(), creg_register_.size()); - std::string masked_val = std::string(length, '0'); - for (size_t rev_pos = 0; rev_pos < length; rev_pos++) { - masked_val[length - 1 - rev_pos] = (mask_bin[mask_bin.size() - 1 - rev_pos] - & creg_register_[creg_register_.size() - 1 - rev_pos]); - } - // remove leading 0's - size_t end_i = masked_val.find('1'); - if (end_i == std::string::npos) - masked_val = "0"; - else - masked_val.erase(0, end_i); - - masked_val = Utils::bin2hex(masked_val); // convert to hex string - // Using string comparison to compare to target value - compared = masked_val.compare(target_val); - } - // check value of compared integer for different comparison operations - bool outcome; - switch (op.bfunc) { - case Operations::RegComparison::Equal: - outcome = (compared == 0); - break; - case Operations::RegComparison::NotEqual: - outcome = (compared != 0); - break; - case Operations::RegComparison::Less: - outcome = (compared < 0); - break; - case Operations::RegComparison::LessEqual: - outcome = (compared <= 0); - break; - case Operations::RegComparison::Greater: - outcome = (compared > 0); - break; - case Operations::RegComparison::GreaterEqual: - outcome = (compared >= 0); - break; - default: - // we shouldn't ever get here - throw std::invalid_argument("Invalid boolean function relation."); - } - // Store outcome in register - if (op.registers.size() > 0) { - const size_t pos = creg_register_.size() - op.registers[0] - 1; - creg_register_[pos] = (outcome) ? '1' : '0'; - } - // Optionally store outcome in memory - if (op.memory.size() > 0) { - const size_t pos = creg_memory_.size() - op.memory[0] - 1; - creg_memory_[pos] = (outcome) ? '1' : '0'; - } -} - -// Apply readout error instruction to classical registers -void ClassicalRegister::apply_roerror(const Operations::Op &op, RngEngine &rng) { - - // Check input is readout error op - if (op.type != Operations::OpType::roerror) { - throw std::invalid_argument("ClassicalRegister::apply_roerror Input is not a readout error op."); - } - - // Get current classical bit (and optionally register bit) values - std::string mem_str; - - // Get values of bits as binary string - // We iterate from the end of the list of memory bits - for (auto it = op.memory.rbegin(); it < op.memory.rend(); ++it) { - auto bit = *it; - mem_str.push_back(creg_memory_[creg_memory_.size() - 1 - bit]); - } - auto mem_val = std::stoull(mem_str, nullptr, 2); - auto outcome = rng.rand_int(op.probs[mem_val]); - auto noise_str = Utils::int2string(outcome, 2, op.memory.size()); - for (size_t pos = 0; pos < op.memory.size(); ++pos) { - auto bit = op.memory[pos]; - creg_memory_[creg_memory_.size() - 1 - bit] = noise_str[noise_str.size() - 1 - pos]; - } - // and the same error to register classical bits if they are used - for (size_t pos = 0; pos < op.registers.size(); ++pos) { - auto bit = op.registers[pos]; - creg_register_[creg_register_.size() - 1 - bit] = noise_str[noise_str.size() - 1 - pos]; - } -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/json.hpp b/quantum/plugins/ibm/aer/src/framework/json.hpp deleted file mode 100755 index 945a0aee0..000000000 --- a/quantum/plugins/ibm/aer/src/framework/json.hpp +++ /dev/null @@ -1,320 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_json_hpp_ -#define _aer_framework_json_hpp_ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "misc/warnings.hpp" -DISABLE_WARNING_PUSH -#include -DISABLE_WARNING_POP -#include "framework/matrix.hpp" - -namespace nl = nlohmann; -using json_t = nlohmann::json; - -//============================================================================ -// JSON Library helper functions -//============================================================================ - -namespace JSON { - -/** - * Load a json_t from a file. If the file name is 'stdin' or '-' the json_t will - * be - * loaded from the standard input stream. - * @param name: file name to load. - * @returns: the loaded json. - */ -inline json_t load(const std::string& name); - -/** - * Check if a key exists in a json_t object. - * @param key: key name. - * @param js: the json_t to search for key. - * @returns: true if the key exists, false otherwise. - */ -inline bool check_key(const std::string& key, const json_t &js); - -/** - * Check if all keys exists in a json_t object. - * @param keys: vector of key names. - * @param js: the json_t to search for keys. - * @returns: true if all keys exists, false otherwise. - */ -inline bool check_keys(const std::vector& keys, const json_t &js); - -/** - * Load a json_t object value into a variable if the key name exists. - * @param var: variable to store key value. - * @param key: key name. - * @param js: the json_t to search for key. - * @returns: true if the keys exists and val was set, false otherwise. - */ -template bool get_value(T &var, const std::string& key, const json_t &js); - -const json_t& get_value(const std::string& key, const json_t &js); - -} // end namespace JSON - -//============================================================================ -// JSON Conversion for complex STL types -//============================================================================ - -namespace std { - -/** - * Convert a complex number to a json list z -> [real(z), imag(z)]. - * @param js a json_t object to contain converted type. - * @param z a complex number to convert. - */ -template void to_json(json_t &js, const std::complex &z); - -/** - * Convert a JSON value to a complex number z. If the json value is a float - * it will be converted to a complex z = (val, 0.). If the json value is a - * length two list it will be converted to a complex z = (val[0], val[1]). - * @param js a json_t object to convert. - * @param z a complex number to contain result. - */ -template void from_json(const json_t &js, std::complex &z); - -/** - * Convert a complex vector to a json list - * v -> [ [real(v[0]), imag(v[0])], ...] - * @param js a json_t object to contain converted type. - * @param vec a complex vector to convert. - */ -template -void to_json(json_t &js, const std::vector> &vec); - -/** - * Convert a JSON list to a complex vector. The input JSON value may be: - * - an object with complex pair values: {'00': [re, im], ... } - * - an object with real pair values: {'00': n, ... } - * - an list with complex values: [ [a0re, a0im], ...] - * - an list with real values: [a0, a1, ....] - * @param js a json_t object to convert. - * @param vec a complex vector to contain result. - */ -template -void from_json(const json_t &js, std::vector> &vec); - -/** - * Convert a map with integer keys to a json. This converts the integer keys - * to strings in the resulting json object. - * @param js a json_t object to contain converted type. - * @param map a map to convert. - */ -template -void to_json(json_t &js, const std::map &map); - -template -void to_json(json_t &js, const std::map &map); - -} // end namespace std. - -/** - * Convert a matrix to a json. - * @param js a json_t object to contain converted type. - * @param mat a matrix to convert. - */ -template -void from_json(const json_t &js, matrix &mat); -template -void to_json(json_t &js, const matrix &mat); - -/******************************************************************************* - * - * Implementations - * - ******************************************************************************/ - -//------------------------------------------------------------------------------ -// JSON Helper Functions -//------------------------------------------------------------------------------ - -json_t JSON::load(const std::string& name) { - if (name == "") { - json_t js; - return js; // Return empty node if no config file - } - json_t js; - if (name == "stdin" || name == "-") // Load from stdin - std::cin >> js; - else { // Load from file - std::ifstream ifile; - ifile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - try { - ifile.open(name); - } catch (std::exception &e) { - throw std::runtime_error(std::string("no such file or directory")); - } - ifile >> js; - } - return js; -} - -bool JSON::check_key(const std::string& key, const json_t &js) { - // returns false if the value is 'null' - if (js.find(key) != js.end() && !js[key].is_null()) - return true; - else - return false; -} - -bool JSON::check_keys(const std::vector& keys, const json_t &js) { - bool pass = true; - for (const auto& s : keys) - pass &= check_key(s, js); - return pass; -} - -template -bool JSON::get_value(T &var, const std::string& key, const json_t &js) { - if (check_key(key, js)) { - var = js[key].get(); - return true; - } else { - return false; - } -} - -const json_t& JSON::get_value(const std::string& key, const json_t &js){ - return js[key]; -} - -//------------------------------------------------------------------------------ -// JSON Conversion -//------------------------------------------------------------------------------ - -template -void std::to_json(json_t &js, const std::complex &z) { - js = std::pair{z.real(), z.imag()}; -} - -template -void std::from_json(const json_t &js, std::complex &z) { - if (js.is_number()) - z = std::complex{js.get()}; - else if (js.is_array() && js.size() == 2) { - z = std::complex{js[0].get(), js[1].get()}; - } else { - throw std::invalid_argument( - std::string("JSON: invalid complex number")); - } -} - -template -void std::to_json(json_t &js, const std::vector> &vec) { - std::vector> out; - for (auto &z : vec) { - out.push_back(std::vector{real(z), imag(z)}); - } - js = out; -} - -template -void std::from_json(const json_t &js, std::vector> &vec) { - std::vector> ret; - if (js.is_array()) { - for (auto &elt : js) - ret.push_back(elt); - vec = ret; - } - else { - throw std::invalid_argument( - std::string("JSON: invalid complex vector.")); - } -} - -// Int-key maps -template -void std::to_json(json_t &js, const std::map &map) { - js = json_t(); - for (const auto &p : map) { - std::string key = std::to_string(p.first); - js[key] = p.second; - } -} - -// Int-key maps -template -void std::to_json(json_t &js, const std::map &map) { - js = json_t(); - for (const auto &p : map) { - std::string key = std::to_string(p.first); - js[key] = p.second; - } -} - -// Matrices -//------------------------------------------------------------------------------ -// Implementation: JSON Conversion -//------------------------------------------------------------------------------ - -template void to_json(json_t &js, const matrix &mat) { - js = json_t(); - size_t rows = mat.GetRows(); - size_t cols = mat.GetColumns(); - for (size_t r = 0; r < rows; r++) { - std::vector mrow; - for (size_t c = 0; c < cols; c++) - mrow.push_back(mat(r, c)); - js.push_back(mrow); - } -} - - -template void from_json(const json_t &js, matrix &mat) { - // Check JSON is an array - if(!js.is_array()) { - throw std::invalid_argument( - std::string("JSON: invalid matrix (not array).")); - } - // Check JSON isn't empty - if(js.empty()) { - throw std::invalid_argument( - std::string("JSON: invalid matrix (empty array).")); - } - // check rows are all same length - bool rows_valid = js.is_array() && !js.empty(); - // Check all entries of array are same size - size_t ncols = js[0].size(); - size_t nrows = js.size(); - for (auto &row : js) - rows_valid &= (row.is_array() && row.size() == ncols); - if(!rows_valid) { - throw std::invalid_argument( - std::string("JSON: invalid matrix (rows different sizes).")); - } - // Matrix looks ok, now we parse it - mat = matrix(nrows, ncols); - for (size_t r = 0; r < nrows; r++) - for (size_t c = 0; c < ncols; c++) - mat(r, c) = js[r][c].get(); -} - -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/json_parser.hpp b/quantum/plugins/ibm/aer/src/framework/json_parser.hpp deleted file mode 100644 index 882af3efe..000000000 --- a/quantum/plugins/ibm/aer/src/framework/json_parser.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_json_parser_hpp_ -#define _aer_framework_json_parser_hpp_ - -#include "json.hpp" - - -namespace AER{ -// This structure is to avoid overload resolving to the wron function, -// as py::objects can always be implicitly converted to json, though -// can break at runtime, or even worse trasnform to json and then to c++ -// without notice. -template -struct Parser {}; - -template <> -struct Parser { - Parser() = delete; - - template - static bool get_value(T &var, const std::string& key, const json_t &js){ - return JSON::get_value(var, key, js); - } - - static bool check_key(const std::string& key, const json_t &js){ - return JSON::check_key(key, js); - } - - static const json_t& get_value(const std::string& key, const json_t &js){ - return JSON::get_value(key, js); - } - - static bool check_keys(const std::vector& keys, const json_t &js) { - return JSON::check_keys(keys, js); - } - - static bool is_array(const json_t &js){ - return js.is_array(); - } - - static bool is_array(const std::string& key, const json_t &js){ - return js[key].is_array(); - } - - static const json_t& get_as_list(const json_t& js){ - if(!is_array(js)){ - throw std::runtime_error("Object is not a list!"); - } - return js; - } - - static const json_t& get_list(const std::string& key, const json_t &js){ - if(!is_array(key, js)){ - throw std::runtime_error("Object " + key + "is not a list!"); - } - return JSON::get_value(key, js); - } - - - static bool is_number(const std::string& key, const json_t &js){ - return js[key].is_number(); - } - - static std::string dump(const json_t& js){ - return js.dump(); - } - - template - static T get_list_elem(const json_t& js, unsigned int i){ - return js[i]; - } -}; -} - -#endif // _aer_framework_json_parser_hpp_ diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/almost_equal.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/almost_equal.hpp deleted file mode 100755 index 387cd9d3b..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/almost_equal.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_almost_equal_hpp_ -#define _aer_framework_linalg_almost_equal_hpp_ - -#include -#include -#include - -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// No silver bullet for floating point comparison techniques. -// With this function the user can at least specify the precision -// If we have numbers closer to 0, then max_diff can be set to a value -// way smaller than epsilon. For numbers larger than 1.0, epsilon will -// scale (the bigger the number, the bigger the epsilon). -template ::value, T>::type > -bool almost_equal(T f1, T f2, - T max_diff = std::numeric_limits::epsilon(), - T max_relative_diff = std::numeric_limits::epsilon()) { - T diff = std::abs(f1 - f2); - if (diff <= max_diff) return true; - - return diff <= max_relative_diff * std::max(std::abs(f1), std::abs(f2)); -} - -template -bool almost_equal(const std::complex& f1, const std::complex& f2, - T max_diff = std::numeric_limits::epsilon(), - T max_relative_diff = std::numeric_limits::epsilon()) { - return almost_equal(f1.real(), f2.real(), max_diff, max_relative_diff) - && almost_equal(f1.imag(), f2.imag(), max_diff, max_relative_diff); -} - -//------------------------------------------------------------------------------ -} // namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/eigensystem.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/eigensystem.hpp deleted file mode 100644 index da0cc10d5..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/eigensystem.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019, 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_eigensystem_hpp_ -#define _aer_framework_linalg_eigensystem_hpp_ - -#include -#include "framework/blas_protos.hpp" -#include "framework/matrix.hpp" - - -/** - * Returns the eigenvalues and eigenvectors - * of a Hermitian matrix. - * Uses the blas function ?heevx - * @param hermitian_matrix: The Hermitian matrix. - * @param eigenvalues: On output: vector with the eignevalues of the matrix (input is overwritten) - * @param eigenvectors: On output: matrix with the eigenvectors stored as columns. - * - * @returns: void - */ -template -void eigensystem_hermitian(const matrix>& hermitian_matrix, - /* out */ std::vector& eigenvalues, - /* out */ matrix>& eigenvectors); - - -template -struct HeevxFuncs; - -template<> -struct HeevxFuncs{ - HeevxFuncs() = delete; - static decltype(zheevx_)& heevx; - static decltype(dlamch_)& lamch; -}; - -decltype(zheevx_)& HeevxFuncs::heevx = zheevx_; -decltype(dlamch_)& HeevxFuncs::lamch = dlamch_; - -template<> -struct HeevxFuncs{ - HeevxFuncs() = delete; - static decltype(cheevx_)& heevx; - static decltype(slamch_)& lamch; -}; - -decltype(cheevx_)& HeevxFuncs::heevx = cheevx_; -decltype(slamch_)& HeevxFuncs::lamch = slamch_; - - -template -void eigensystem_hermitian(const matrix>& hermitian_matrix, - std::vector& eigenvalues, - matrix>& eigenvectors) { - if ( hermitian_matrix.GetRows() != hermitian_matrix.GetColumns() ) { - throw std::runtime_error("Input matrix in eigensystem_hermitian " - "function is not a square matrix."); - } - - int n = static_cast(hermitian_matrix.GetLD()); - int ldz{n}, lda{n}, lwork{2*n}; - int il{0}, iu{0}; // not referenced if range='A' - T vl{0.0}, vu{0.0}; // not referenced if range='A' - char cmach{'S'}; - T abstol{static_cast(2.0*HeevxFuncs::lamch(&cmach))}; - int m{0}; // number of eigenvalues found - int info{0}; - - eigenvectors.resize(ldz, n); - eigenvalues.clear(); - eigenvalues.resize(n); - matrix> heevx_copy{hermitian_matrix}; - auto work = std::vector>(lwork, {0.0, 0.0}); - auto rwork = std::vector(7*n, 0.0); - auto iwork = std::vector(5*n, 0); - auto ifail = std::vector(n, 0); - - HeevxFuncs::heevx(&AerBlas::Jobz[0], &AerBlas::Range[0], &AerBlas::UpLo[0], &n, - heevx_copy.data(), &lda, &vl, &vu, &il, &iu, - &abstol, &m, eigenvalues.data(), eigenvectors.data(), &ldz, work.data(), - &lwork, rwork.data(), iwork.data(), ifail.data(), &info); - - if(info){ - throw std::runtime_error("Something went wrong in heevx call within eigensystem_hermitian funcion. " - "Check that input matrix is really hermitian"); - } -} - -#endif // _aer_framework_linalg_eigensystem_hpp_ diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/enable_if_numeric.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/enable_if_numeric.hpp deleted file mode 100755 index e99d55a3e..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/enable_if_numeric.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_enable_if_numeric_hpp_ -#define _aer_framework_linalg_enable_if_numeric_hpp_ - -#include -#include - -// Type check template to enable functions if type is a numeric scalar -// (integer, float, or complex float) -template -struct is_numeric_scalar - : std::integral_constant< - bool, std::is_arithmetic::value || - std::is_same, - typename std::remove_cv::type>::value || - std::is_same, - typename std::remove_cv::type>::value || - std::is_same, - typename std::remove_cv::type>::value> {}; - -template -using enable_if_numeric_t = std::enable_if_t::value>; - -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linalg.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linalg.hpp deleted file mode 100755 index 1788feedf..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linalg.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_hpp_ -#define _aer_framework_linalg_hpp_ - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/eigensystem.hpp" -#include "framework/linalg/linops/linops_aer_vector.hpp" -#include "framework/linalg/linops/linops_array.hpp" -#include "framework/linalg/linops/linops_generic.hpp" -#include "framework/linalg/linops/linops_json.hpp" -#include "framework/linalg/linops/linops_map.hpp" -#include "framework/linalg/linops/linops_matrix.hpp" -#include "framework/linalg/linops/linops_unordered_map.hpp" -#include "framework/linalg/linops/linops_vector.hpp" -#include "framework/linalg/square.hpp" - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_aer_vector.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_aer_vector.hpp deleted file mode 100755 index ba6ebc190..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_aer_vector.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_aer_vector_hpp_ -#define _aer_framework_linalg_linops_aer_vector_hpp_ - -#include -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/vector.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that work for numeric vector types - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -Vector add(const Vector& lhs, const Vector& rhs) { - return lhs + rhs; -} - -template > -Vector& iadd(Vector& lhs, const Vector& rhs) { - lhs += rhs; - return lhs; -} - -template > -Vector sub(const Vector& lhs, const Vector& rhs) { - return lhs - rhs; -} - -template > -Vector& isub(Vector& lhs, const Vector& rhs) { - lhs -= rhs; - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -Vector& iadd(Vector& data, const Scalar& val) { - const T cast_val(val); - std::for_each(data.data(), data.data() + data.size(), - [&cast_val](T& a)->T{ a += cast_val; }); - return data; -} - -template , - typename = enable_if_numeric_t> -Vector add(const Vector& data, const Scalar& val) { - auto ret = data; - return iadd(data, val); -} - - -template , - typename = enable_if_numeric_t> -Vector sub(const Vector& data, const Scalar& val) { - return add(data, -val); -} - -template , - typename = enable_if_numeric_t> -Vector& isub(Vector& data, const Scalar& val) { - return iadd(data, -val); -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -Vector& imul(Vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - data *= T(val); - return data; -} - -template , - typename = enable_if_numeric_t> -Vector mul(const Vector& data, const Scalar& val) { - auto ret = data; - return imul(ret, val); -} - -template , - typename = enable_if_numeric_t> -Vector& idiv(Vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - data /= T(val); - return data; -} - - -template , - typename = enable_if_numeric_t> -Vector div(const Vector& data, const Scalar& val) { - auto ret = data; - return idiv(ret, val); -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_array.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_array.hpp deleted file mode 100755 index 1211cb7db..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_array.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_array_hpp_ -#define _aer_framework_linalg_linops_array_hpp_ - -#include -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that work for numeric vector types - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -std::array& iadd(std::array& lhs, const std::array& rhs) { - std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), - std::plus()); - return lhs; -} - -template > -std::array add(const std::array& lhs, const std::array& rhs) { - std::array result = lhs; - return iadd(result, rhs); -} - -template > -std::array& isub(std::array& lhs, const std::array& rhs) { - std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), - std::minus()); - return lhs; -} - -template > -std::array sub(const std::array& lhs, const std::array& rhs) { - std::array result = lhs; - return isub(result, rhs); -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::array& iadd(std::array& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::plus(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::array add(const std::array& data, const Scalar& val) { - std::array result = data; - return iadd(result, val); -} - -template , - typename = enable_if_numeric_t> -std::array& isub(std::array& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::minus(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::array sub(const std::array& data, const Scalar& val) { - std::array result = data; - return isub(result, val); -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::array& imul(std::array& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::multiplies(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::array mul(const std::array& data, const Scalar& val) { - std::array result = data; - return imul(result, val); -} - -template , - typename = enable_if_numeric_t> -std::array& idiv(std::array& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::divides(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::array div(const std::array& data, const Scalar& val) { - std::array result = data; - return idiv(result, val); -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_generic.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_generic.hpp deleted file mode 100755 index f85b04e37..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_generic.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_generic_hpp_ -#define _aer_framework_linalg_linops_generic_hpp_ - -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that for generic types that support +,-,*,/ and +=, -=, *=, /= overloads - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template -T add(const T& lhs, const T& rhs) { - return std::plus()(lhs, rhs); -} - -template -T& iadd(T& lhs, const T& rhs) { - lhs = std::plus()(lhs, rhs); - return lhs; -} - -template -T sub(const T& lhs, const T& rhs) { - return std::minus()(lhs, rhs); -} - -template -T& isub(T& lhs, const T& rhs) { - lhs = std::minus()(lhs, rhs); - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template > -T add(const T& data, const Scalar& val) { - return std::plus()(data, val); -} - -template > -T& iadd(T& data, const Scalar& val) { - data = std::plus()(data, val); - return data; -} - -template > -T sub(const T& data, const Scalar& val) { - return std::minus()(data, val); -} - -template > -T& isub(T& data, const Scalar& val) { - data = std::minus()(data, val); - return data; -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- -template > -T mul(const T& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - return std::multiplies()(data, val); -} - -template > -T& imul(T& data, const Scalar& val) { - if (!almost_equal(val, 1)) { - data = std::multiplies()(data, val); - } - return data; -} - -template > -T div(const T& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - return std::divides()(data, val); -} - -template > -T& idiv(T& data, const Scalar& val) { - if (!almost_equal(val, 1)) { - data = std::divides()(data, val); - } - return data; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_json.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_json.hpp deleted file mode 100755 index 8473bfbb8..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_json.hpp +++ /dev/null @@ -1,242 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_json_hpp_ -#define _aer_framework_linalg_linops_json_hpp_ - -#include "framework/json.hpp" -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that for numeric json that support +,-,*,/ and +=, -=, *=, /= overloads - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -inline json_t& iadd(json_t& lhs, const json_t& rhs) { - // Null case - if (lhs.is_null()) { - lhs = rhs; - return lhs; - } - if (rhs.is_null()) { - return lhs; - } - // Terminating case - if (lhs.is_number() && rhs.is_number()) { - lhs = double(lhs) + double(rhs); - return lhs; - } - // Recursive cases - if (lhs.is_array() && rhs.is_array() && lhs.size() == rhs.size()) { - for (size_t pos = 0; pos < lhs.size(); pos++) { - iadd(lhs[pos], rhs[pos]); - } - } else if (lhs.is_object() && rhs.is_object()) { - for (auto it = rhs.begin(); it != rhs.end(); ++it) { - iadd(lhs[it.key()], it.value()); - } - } else { - throw std::invalid_argument("Input JSONs cannot be added."); - } - return lhs; -} - -inline json_t add(const json_t& lhs, const json_t& rhs) { - json_t result = lhs; - return iadd(result, rhs); -} - -inline json_t& isub(json_t& lhs, const json_t& rhs) { - // Null case - if (rhs.is_null()) { - return lhs; - } - // Terminating case - if (lhs.is_number() && rhs.is_number()) { - lhs = double(lhs) - double(rhs); - return lhs; - } - // Recursive cases - if (lhs.is_array() && rhs.is_array() && lhs.size() == rhs.size()) { - for (size_t pos = 0; pos < lhs.size(); pos++) { - isub(lhs[pos], rhs[pos]); - } - } else if (lhs.is_object() && rhs.is_object()) { - for (auto it = rhs.begin(); it != rhs.end(); ++it) { - isub(lhs[it.key()], it.value()); - } - } else { - throw std::invalid_argument("Input JSONs cannot be subtracted."); - } - return lhs; -} - -template -json_t sub(const T& lhs, const json_t& rhs) { - json_t result = lhs; - return isub(result, rhs); -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template > -json_t& iadd(json_t& data, const Scalar& val) { - // Null case - if (val == 0) { - return data; - } - // Terminating case - if (data.is_number()) { - data = double(data) + val; - return data; - } - // Recursive cases - if (data.is_array()) { - for (size_t pos = 0; pos < data.size(); pos++) { - iadd(data[pos], val); - } - } else if (data.is_object()) { - for (auto it = data.begin(); it != data.end(); ++it) { - iadd(data[it.key()], val); - } - } else { - throw std::invalid_argument("Input JSON does not support affine addition."); - } - return data; -} - -template > -json_t add(const json_t& data, const Scalar& val) { - json_t result = data; - return iadd(result, val); -} - -template > -json_t& isub(json_t& data, const Scalar& val) { - // Null case - if (val == 0) { - return data; - } - // Terminating case - if (data.is_number()) { - data = double(data) - val; - return data; - } - // Recursive cases - if (data.is_array()) { - for (size_t pos = 0; pos < data.size(); pos++) { - isub(data[pos], val); - } - } else if (data.is_object()) { - for (auto it = data.begin(); it != data.end(); ++it) { - isub(data[it.key()], val); - } - } else { - throw std::invalid_argument( - "Input JSON does not support affine subtraction."); - } - return data; -} - -template > -json_t sub(const json_t& data, const Scalar& val) { - json_t result = data; - return isub(result, val); -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- - -template > -json_t& imul(json_t& data, const Scalar& val) { - // Trival case - if (almost_equal(val, 1)) { - return data; - } - // Terminating case - if (data.is_number()) { - data = double(data) * val; - return data; - } - // Recursive cases - if (data.is_array()) { - for (size_t pos = 0; pos < data.size(); pos++) { - imul(data[pos], val); - } - return data; - } - if (data.is_object()) { - for (auto it = data.begin(); it != data.end(); ++it) { - imul(data[it.key()], val); - } - return data; - } - throw std::invalid_argument( - "Input JSON does not support scalar multiplication."); -} - -template > -json_t mul(const json_t& data, const Scalar& val) { - // Null case - json_t result = data; - return imul(result, val); -} - -template > -json_t& idiv(json_t& data, const Scalar& val) { - // Trival case - if (almost_equal(val, 1)) { - return data; - } - // Terminating case - if (data.is_number()) { - data = double(data) / val; - return data; - } - // Recursive cases - if (data.is_array()) { - for (size_t pos = 0; pos < data.size(); pos++) { - idiv(data[pos], val); - } - return data; - } - if (data.is_object()) { - for (auto it = data.begin(); it != data.end(); ++it) { - idiv(data[it.key()], val); - } - return data; - } - throw std::invalid_argument("Input JSON does not support scalar division."); -} - -template > -json_t div(const json_t& data, const Scalar& val) { - // Null case - json_t result = data; - return idiv(result, val); -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_map.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_map.hpp deleted file mode 100755 index f42cb80c6..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_map.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_map_hpp_ -#define _aer_framework_linalg_linops_map_hpp_ - -#include -#include -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that work for numeric map types - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -std::map add(const std::map& lhs, - const std::map& rhs) { - std::map result = lhs; - for (const auto &pair : rhs) { - result[pair.first] = std::plus()(result[pair.first], pair.second); - } - return result; -} - -template > -std::map& iadd(std::map& lhs, - const std::map& rhs) { - for (const auto &pair : rhs) { - lhs[pair.first] = std::plus()(lhs[pair.first], pair.second); - } - return lhs; -} - -template > -std::map sub(const std::map& lhs, - const std::map& rhs) { - std::map result = lhs; - for (const auto &pair : rhs) { - result[pair.first] = std::minus()(result[pair.first], pair.second); - } - return result; -} - -template > -std::map& isub(std::map& lhs, - const std::map& rhs) { - for (const auto &pair : rhs) { - lhs[pair.first] = std::minus()(lhs[pair.first], pair.second); - } - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::map add(const std::map& data, - const Scalar& val) { - std::map result; - for (const auto &pair : data) { - result[pair.first] = std::plus()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::map& iadd(std::map& data, - const Scalar& val) { - for (const auto &pair : data) { - data[pair.first] = std::plus()(data[pair.first], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -std::map sub(const std::map& data, - const Scalar& val) { - std::map result; - for (const auto &pair : data) { - result[pair.first] = std::minus()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::map& isub(std::map& data, - const Scalar& val) { - for (const auto &pair : data) { - data[pair.first] = std::plus()(data[pair.first], val); - } - return data; -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- - -template , - typename = enable_if_numeric_t> -std::map mul(const std::map& data, - const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::map result; - for (const auto &pair : data) { - result[pair.first] = std::multiplies()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::map& imul(std::map& data, - const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (const auto &pair : data) { - data[pair.first] = std::multiplies()(data[pair.first], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -std::map div(const std::map& data, - const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::map result; - for (const auto &pair : data) { - result[pair.first] = std::divides()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::map& idiv(std::map& data, - const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (const auto &pair : data) { - data[pair.first] = std::divides()(data[pair.first], val); - } - return data; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_matrix.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_matrix.hpp deleted file mode 100755 index 4b510389c..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_matrix.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_matrix_hpp_ -#define _aer_framework_linalg_linops_matrix_hpp_ - -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" -#include "framework/matrix.hpp" - -namespace AER { -namespace Linalg { - -// This defines some missing overloads for matrix class -// It should really be added to the matrix class - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -matrix add(const matrix& lhs, const matrix& rhs) { - return lhs + rhs; -} - -template > -matrix& iadd(matrix& lhs, const matrix& rhs) { - lhs = lhs + rhs; - return lhs; -} - -template > -matrix sub(const matrix& lhs, const matrix& rhs) { - return lhs - rhs; -} - -template > -matrix& isub(matrix& lhs, const matrix& rhs) { - lhs = lhs - rhs; - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -matrix& iadd(matrix& data, const Scalar& val) { - if (val == 0) { - return data; - } - for (size_t j = 0; j < data.size(); j++) { - data[j] = std::plus()(data[j], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -matrix add(const matrix& data, const Scalar& val) { - matrix result(data); - return iadd(result, val); -} - -template , - typename = enable_if_numeric_t> -matrix sub(const matrix& data, const Scalar& val) { - return add(data, -val); -} - -template , - typename = enable_if_numeric_t> -matrix& isub(matrix& data, const Scalar& val) { - return iadd(data, -val); -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- - -template , - typename = enable_if_numeric_t> -matrix& imul(matrix& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (size_t j = 0; j < data.size(); j++) { - data[j] = std::multiplies()(data[j], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -matrix mul(const matrix& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - matrix result = data; - imul(result, val); - return result; -} - -template , - typename = enable_if_numeric_t> -matrix& idiv(matrix& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (size_t j = 0; j < data.size(); j++) { - data[j] = std::divides()(data[j], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -matrix div(const matrix& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - matrix result = data; - idiv(result, val); - return result; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_unordered_map.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_unordered_map.hpp deleted file mode 100755 index 7df754b5d..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_unordered_map.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_unordered_map_hpp_ -#define _aer_framework_linalg_linops_unordered_map_hpp_ - -#include -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that work for numeric unordered_map types - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -std::unordered_map add( - const std::unordered_map& lhs, - const std::unordered_map& rhs) { - std::unordered_map result = lhs; - for (const auto &pair : rhs) { - result[pair.first] = std::plus()(result[pair.first], pair.second); - } - return result; -} - -template > -std::unordered_map& iadd( - std::unordered_map& lhs, - const std::unordered_map& rhs) { - for (const auto &pair : rhs) { - lhs[pair.first] = std::plus()(lhs[pair.first], pair.second); - } - return lhs; -} - -template > -std::unordered_map sub( - const std::unordered_map& lhs, - const std::unordered_map& rhs) { - std::unordered_map result = lhs; - for (const auto &pair : rhs) { - result[pair.first] = std::minus()(result[pair.first], pair.second); - } - return result; -} - -template > -std::unordered_map& isub( - std::unordered_map& lhs, - const std::unordered_map& rhs) { - for (const auto &pair : rhs) { - lhs[pair.first] = std::minus()(lhs[pair.first], pair.second); - } - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::unordered_map add( - const std::unordered_map& data, const Scalar& val) { - std::unordered_map result; - for (const auto &pair : data) { - result[pair.first] = std::plus()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map& iadd( - std::unordered_map& data, const Scalar& val) { - for (const auto &pair : data) { - data[pair.first] = std::plus()(data[pair.first], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map sub( - const std::unordered_map& data, const Scalar& val) { - std::unordered_map result; - for (const auto &pair : data) { - result[pair.first] = std::minus()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map& isub( - std::unordered_map& data, const Scalar& val) { - for (const auto &pair : data) { - data[pair.first] = std::plus()(data[pair.first], val); - } - return data; -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- - -template , - typename = enable_if_numeric_t> -std::unordered_map mul( - const std::unordered_map& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::unordered_map result; - for (const auto &pair : data) { - result[pair.first] = std::multiplies()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map& imul( - std::unordered_map& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (const auto &pair : data) { - data[pair.first] = std::multiplies()(data[pair.first], val); - } - return data; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map div( - const std::unordered_map& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::unordered_map result; - for (const auto &pair : data) { - result[pair.first] = std::divides()(pair.second, val); - } - return result; -} - -template , - typename = enable_if_numeric_t> -std::unordered_map& idiv( - std::unordered_map& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - for (const auto &pair : data) { - data[pair.first] = std::divides()(data[pair.first], val); - } - return data; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_vector.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_vector.hpp deleted file mode 100755 index 759442d9f..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/linops/linops_vector.hpp +++ /dev/null @@ -1,172 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_linops_vector_hpp_ -#define _aer_framework_linalg_linops_vector_hpp_ - -#include -#include - -#include "framework/linalg/almost_equal.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions add, sub, mul, div and iadd, imul, isub, idiv -// that work for numeric vector types - -//---------------------------------------------------------------------------- -// Linear operations -//---------------------------------------------------------------------------- -template > -std::vector add(const std::vector& lhs, const std::vector& rhs) { - if (lhs.size() != rhs.size()) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::vector result; - result.reserve(lhs.size()); - std::transform(lhs.begin(), lhs.end(), rhs.begin(), - std::back_inserter(result), std::plus()); - return result; -} - -template > -std::vector& iadd(std::vector& lhs, const std::vector& rhs) { - if (lhs.size() != rhs.size()) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), - std::plus()); - return lhs; -} - -template > -std::vector sub(const std::vector& lhs, const std::vector& rhs) { - if (lhs.size() != rhs.size()) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::vector result; - result.reserve(lhs.size()); - std::transform(lhs.begin(), lhs.end(), rhs.begin(), - std::back_inserter(result), std::minus()); - return result; -} - -template > -std::vector& isub(std::vector& lhs, const std::vector& rhs) { - if (lhs.size() != rhs.size()) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), - std::minus()); - return lhs; -} - -//---------------------------------------------------------------------------- -// Affine operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::vector add(const std::vector& data, const Scalar& val) { - std::vector result; - result.reserve(data.size()); - std::transform(data.begin(), data.end(), std::back_inserter(result), - std::bind(std::plus(), std::placeholders::_1, val)); - return result; -} - -template , - typename = enable_if_numeric_t> -std::vector& iadd(std::vector& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::plus(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::vector sub(const std::vector& data, const Scalar& val) { - std::vector result; - result.reserve(data.size()); - std::transform(data.begin(), data.end(), std::back_inserter(result), - std::bind(std::minus(), std::placeholders::_1, val)); - return result; -} - -template , - typename = enable_if_numeric_t> -std::vector& isub(std::vector& data, const Scalar& val) { - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::minus(), std::placeholders::_1, val)); - return data; -} - -//---------------------------------------------------------------------------- -// Scalar operations -//---------------------------------------------------------------------------- -template , - typename = enable_if_numeric_t> -std::vector mul(const std::vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::vector result; - result.reserve(data.size()); - std::transform(data.begin(), data.end(), std::back_inserter(result), - std::bind(std::multiplies(), std::placeholders::_1, val)); - return result; -} - -template , - typename = enable_if_numeric_t> -std::vector& imul(std::vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::multiplies(), std::placeholders::_1, val)); - return data; -} - -template , - typename = enable_if_numeric_t> -std::vector div(const std::vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::vector result; - result.reserve(data.size()); - std::transform(data.begin(), data.end(), std::back_inserter(result), - std::bind(std::divides(), std::placeholders::_1, val)); - return result; -} - -template , - typename = enable_if_numeric_t> -std::vector& idiv(std::vector& data, const Scalar& val) { - if (almost_equal(val, 1)) { - return data; - } - std::transform(data.begin(), data.end(), data.begin(), - std::bind(std::divides(), std::placeholders::_1, val)); - return data; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils.hpp deleted file mode 100755 index bd6903dde..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_matrix_utils_hpp_ -#define _aer_framework_linalg_matrix_utils_hpp_ - -#include "framework/linalg/matrix_utils/matrix_defs.hpp" -#include "framework/linalg/matrix_utils/vmatrix_defs.hpp" -#include "framework/linalg/matrix_utils/smatrix_defs.hpp" - -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/matrix_defs.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/matrix_defs.hpp deleted file mode 100755 index 4b356399b..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/matrix_defs.hpp +++ /dev/null @@ -1,395 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_matrix_utils_matrix_defs_hpp_ -#define _aer_framework_linalg_matrix_utils_matrix_defs_hpp_ - -#include -#include -#include -#include - -#include "framework/types.hpp" -#include "framework/utils.hpp" - -namespace AER { -namespace Linalg { - -//------------------------------------------------------------------------------ -// Static matrices -//------------------------------------------------------------------------------ - -class Matrix { -public: - // Single-qubit gates - const static cmatrix_t I; // name: "id" - const static cmatrix_t X; // name: "x" - const static cmatrix_t Y; // name: "y" - const static cmatrix_t Z; // name: "z" - const static cmatrix_t H; // name: "h" - const static cmatrix_t S; // name: "s" - const static cmatrix_t SDG; // name: "sdg" - const static cmatrix_t T; // name: "t" - const static cmatrix_t TDG; // name: "tdg" - const static cmatrix_t SX; // name: "sx" - const static cmatrix_t SXDG;// name: "sxdg" - const static cmatrix_t X90; // name: "x90" - - // Two-qubit gates - const static cmatrix_t CX; // name: "cx" - const static cmatrix_t CY; // name: "cy" - const static cmatrix_t CZ; // name: "cz" - const static cmatrix_t SWAP; // name: "swap" - - // Identity Matrix - static cmatrix_t identity(size_t dim); - - // Single-qubit waltz gates - static cmatrix_t u1(double lam); - static cmatrix_t u2(double phi, double lam); - static cmatrix_t u3(double theta, double phi, double lam); - static cmatrix_t u4(double theta, double phi, double lam, double gamma); - - // Single-qubit rotation gates - static cmatrix_t r(double phi, double lam); - static cmatrix_t rx(double theta); - static cmatrix_t ry(double theta); - static cmatrix_t rz(double theta); - - // Two-qubit rotation gates - static cmatrix_t rxx(double theta); - static cmatrix_t ryy(double theta); - static cmatrix_t rzz(double theta); - static cmatrix_t rzx(double theta); // rotation around Tensor(X, Z) - - // Phase Gates - static cmatrix_t phase(double theta); - static cmatrix_t phase_diag(double theta); - static cmatrix_t cphase(double theta); - static cmatrix_t cphase_diag(double theta); - - // Controlled-single qubit gate - static cmatrix_t cu(double theta, double phi, double lam, double gamma); - - // Complex arguments are implemented by taking std::real - // of the input - static cmatrix_t u1(complex_t lam) { return phase(std::real(lam)); } - static cmatrix_t u2(complex_t phi, complex_t lam) { - return u2(std::real(phi), std::real(lam)); - } - static cmatrix_t u3(complex_t theta, complex_t phi, complex_t lam) { - return u3(std::real(theta), std::real(phi), std::real(lam)); - }; - static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - }; - static cmatrix_t r(complex_t theta, complex_t phi) { - return r(std::real(theta), std::real(phi)); - } - static cmatrix_t rx(complex_t theta) { return rx(std::real(theta)); } - static cmatrix_t ry(complex_t theta) { return ry(std::real(theta)); } - static cmatrix_t rz(complex_t theta) { return rz(std::real(theta)); } - static cmatrix_t rxx(complex_t theta) { return rxx(std::real(theta)); } - static cmatrix_t ryy(complex_t theta) { return ryy(std::real(theta)); } - static cmatrix_t rzz(complex_t theta) { return rzz(std::real(theta)); } - static cmatrix_t rzx(complex_t theta) { return rzx(std::real(theta)); } - static cmatrix_t phase(complex_t theta) { return phase(std::real(theta)); } - static cmatrix_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } - static cmatrix_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cmatrix_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - } - - // Return the matrix for a named matrix string - // Allowed names correspond to all the const static single-qubit - // and two-qubit gate members - static const cmatrix_t from_name(const std::string &name) { - return *label_map_.at(name); - } - - // Check if the input name string is allowed - static bool allowed_name(const std::string &name) { - return (label_map_.find(name) != label_map_.end()); - } - -private: - // Lookup table that returns a pointer to the static data member - const static stringmap_t label_map_; -}; - -//============================================================================== -// Implementations -//============================================================================== - -const cmatrix_t Matrix::I = - Utils::make_matrix({{{1, 0}, {0, 0}}, {{0, 0}, {1, 0}}}); - -const cmatrix_t Matrix::X = - Utils::make_matrix({{{0, 0}, {1, 0}}, {{1, 0}, {0, 0}}}); - -const cmatrix_t Matrix::Y = - Utils::make_matrix({{{0, 0}, {0, -1}}, {{0, 1}, {0, 0}}}); - -const cmatrix_t Matrix::Z = - Utils::make_matrix({{{1, 0}, {0, 0}}, {{0, 0}, {-1, 0}}}); - -const cmatrix_t Matrix::S = - Utils::make_matrix({{{1, 0}, {0, 0}}, {{0, 0}, {0, 1}}}); - -const cmatrix_t Matrix::SDG = - Utils::make_matrix({{{1, 0}, {0, 0}}, {{0, 0}, {0, -1}}}); - -const cmatrix_t Matrix::T = Utils::make_matrix( - {{{1, 0}, {0, 0}}, {{0, 0}, {1 / std::sqrt(2), 1 / std::sqrt(2)}}}); - -const cmatrix_t Matrix::TDG = Utils::make_matrix( - {{{1, 0}, {0, 0}}, {{0, 0}, {1 / std::sqrt(2), -1 / std::sqrt(2)}}}); - -const cmatrix_t Matrix::H = Utils::make_matrix( - {{{1 / std::sqrt(2.), 0}, {1 / std::sqrt(2.), 0}}, - {{1 / std::sqrt(2.), 0}, {-1 / std::sqrt(2.), 0}}}); - -const cmatrix_t Matrix::SX = Utils::make_matrix( - {{{0.5, 0.5}, {0.5, -0.5}}, {{0.5, -0.5}, {0.5, 0.5}}}); - -const cmatrix_t Matrix::SXDG = Utils::make_matrix( - {{{0.5, -0.5}, {0.5, 0.5}}, {{0.5, 0.5}, {0.5, -0.5}}}); - -const cmatrix_t Matrix::X90 = Utils::make_matrix( - {{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}}, - {{0, -1. / std::sqrt(2.)}, {1. / std::sqrt(2.), 0}}}); - -const cmatrix_t Matrix::CX = - Utils::make_matrix({{{1, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {0, 0}, {1, 0}}, - {{0, 0}, {0, 0}, {1, 0}, {0, 0}}, - {{0, 0}, {1, 0}, {0, 0}, {0, 0}}}); - -const cmatrix_t Matrix::CY = - Utils::make_matrix({{{1, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {0, 0}, {0, -1}}, - {{0, 0}, {0, 0}, {1, 0}, {0, 0}}, - {{0, 0}, {0, 1}, {0, 0}, {0, 0}}}); - -const cmatrix_t Matrix::CZ = - Utils::make_matrix({{{1, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {1, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {1, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {0, 0}, {-1, 0}}}); - -const cmatrix_t Matrix::SWAP = - Utils::make_matrix({{{1, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {1, 0}, {0, 0}}, - {{0, 0}, {1, 0}, {0, 0}, {0, 0}}, - {{0, 0}, {0, 0}, {0, 0}, {1, 0}}}); - -// Lookup table -const stringmap_t Matrix::label_map_ = { - {"id", &Matrix::I}, {"x", &Matrix::X}, {"y", &Matrix::Y}, - {"z", &Matrix::Z}, {"h", &Matrix::H}, {"s", &Matrix::S}, - {"sdg", &Matrix::SDG}, {"t", &Matrix::T}, {"tdg", &Matrix::TDG}, - {"x90", &Matrix::X90}, {"cx", &Matrix::CX}, {"cy", &Matrix::CY}, - {"cz", &Matrix::CZ}, {"swap", &Matrix::SWAP}, {"sx", &Matrix::SX}, - {"sxdg", &Matrix::SXDG}, {"delay", &Matrix::I}}; - -cmatrix_t Matrix::identity(size_t dim) { - cmatrix_t mat(dim, dim); - for (size_t j = 0; j < dim; j++) - mat(j, j) = {1.0, 0.0}; - return mat; -} - -cmatrix_t Matrix::u1(double lambda) { - return phase(lambda); -} - -cmatrix_t Matrix::u2(double phi, double lambda) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - const complex_t invsqrt2(1. / std::sqrt(2), 0.); - mat(0, 0) = invsqrt2; - mat(0, 1) = -std::exp(i * lambda) * invsqrt2; - mat(1, 0) = std::exp(i * phi) * invsqrt2; - mat(1, 1) = std::exp(i * (phi + lambda)) * invsqrt2; - return mat; -} - -cmatrix_t Matrix::u3(double theta, double phi, double lambda) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - mat(0, 0) = std::cos(0.5 * theta); - mat(0, 1) = -std::exp(i * lambda) * std::sin(0.5 * theta); - mat(1, 0) = std::exp(i * phi) * std::sin(0.5 * theta); - mat(1, 1) = std::exp(i * (phi + lambda)) * std::cos(0.5 * theta); - return mat; -} - -cmatrix_t Matrix::u4(double theta, double phi, double lambda, double gamma) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - mat(0, 0) = std::exp(i * gamma) * std::cos(0.5 * theta); - mat(0, 1) = -std::exp(i * (lambda + gamma)) * std::sin(0.5 * theta); - mat(1, 0) = std::exp(i * (phi + gamma)) * std::sin(0.5 * theta); - mat(1, 1) = std::exp(i * (phi + lambda + gamma)) * std::cos(0.5 * theta); - return mat; -} - -cmatrix_t Matrix::r(double theta, double phi) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - mat(0, 0) = std::cos(0.5 * theta); - mat(0, 1) = -i * std::exp(-i * phi) * std::sin(0.5 * theta); - mat(1, 0) = -i * std::exp(i * phi) * std::sin(0.5 * theta); - mat(1, 1) = std::cos(0.5 * theta); - return mat; -} - -cmatrix_t Matrix::rx(double theta) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - mat(0, 0) = std::cos(0.5 * theta); - mat(0, 1) = -i * std::sin(0.5 * theta); - mat(1, 0) = mat(0, 1); - mat(1, 1) = mat(0, 0); - return mat; -} - -cmatrix_t Matrix::ry(double theta) { - cmatrix_t mat(2, 2); - mat(0, 0) = std::cos(0.5 * theta); - mat(0, 1) = -1.0 * std::sin(0.5 * theta); - mat(1, 0) = -mat(0, 1); - mat(1, 1) = mat(0, 0); - return mat; -} - -cmatrix_t Matrix::rz(double theta) { - cmatrix_t mat(2, 2); - const complex_t i(0., 1.); - mat(0, 0) = std::exp(-i * 0.5 * theta); - mat(1, 1) = std::exp(i * 0.5 * theta); - return mat; -} - -cmatrix_t Matrix::rxx(double theta) { - cmatrix_t mat(4, 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat(0, 0) = cost; - mat(0, 3) = -i * sint; - mat(1, 1) = cost; - mat(1, 2) = -i * sint; - mat(2, 1) = -i * sint; - mat(2, 2) = cost; - mat(3, 0) = -i * sint; - mat(3, 3) = cost; - return mat; -} - -cmatrix_t Matrix::ryy(double theta) { - cmatrix_t mat(4, 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat(0, 0) = cost; - mat(0, 3) = i * sint; - mat(1, 1) = cost; - mat(1, 2) = -i * sint; - mat(2, 1) = -i * sint; - mat(2, 2) = cost; - mat(3, 0) = i * sint; - mat(3, 3) = cost; - return mat; -} - -cmatrix_t Matrix::rzz(double theta) { - cmatrix_t mat(4, 4); - const complex_t i(0., 1.); - const complex_t exp_p = std::exp(i * 0.5 * theta); - const complex_t exp_m = std::exp(-i * 0.5 * theta); - mat(0, 0) = exp_m; - mat(1, 1) = exp_p; - mat(2, 2) = exp_p; - mat(3, 3) = exp_m; - return mat; -} - -cmatrix_t Matrix::rzx(double theta) { - cmatrix_t mat(4, 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat(0, 0) = cost; - mat(0, 2) = -i * sint; - mat(1, 1) = cost; - mat(1, 3) = i * sint; - mat(2, 0) = -i * sint; - mat(2, 2) = cost; - mat(3, 1) = i * sint; - mat(3, 3) = cost; - return mat; -} - -cmatrix_t Matrix::cu(double theta, double phi, double lambda, double gamma) { - cmatrix_t mat(4, 4); - const complex_t i(0., 1.); - mat(0, 0) = 1; - mat(2, 2) = 1; - mat(1, 1) = std::exp(i * gamma) * std::cos(0.5 * theta); - mat(1, 3) = -std::exp(i * (lambda + gamma)) * std::sin(0.5 * theta); - mat(3, 1) = std::exp(i * (phi + gamma)) * std::sin(0.5 * theta); - mat(3, 3) = std::exp(i * (phi + lambda + gamma)) * std::cos(0.5 * theta); - return mat; -} - -cmatrix_t Matrix::phase(double theta) { - cmatrix_t mat(2, 2); - mat(0, 0) = 1; - mat(1, 1) = std::exp(complex_t(0.0, theta)); - return mat; -} - -cmatrix_t Matrix::phase_diag(double theta) { - cmatrix_t mat(1, 2); - mat(0, 0) = 1; - mat(0, 1) = std::exp(complex_t(0.0, theta)); - return mat; -} - -cmatrix_t Matrix::cphase(double theta) { - cmatrix_t mat(4, 4); - mat(0, 0) = 1; - mat(1, 1) = 1; - mat(2, 2) = 1; - mat(3, 3) = std::exp(complex_t(0.0, theta)); - return mat; -} - -cmatrix_t Matrix::cphase_diag(double theta) { - cmatrix_t mat(1, 4); - mat(0, 0) = 1; - mat(0, 1) = 1; - mat(0, 2) = 1; - mat(0, 3) = std::exp(complex_t(0.0, theta)); - return mat; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/smatrix_defs.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/smatrix_defs.hpp deleted file mode 100755 index 2d3a73cc4..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/smatrix_defs.hpp +++ /dev/null @@ -1,318 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_matrix_utils_smatrix_defs_hpp_ -#define _aer_framework_linalg_matrix_utils_smatrix_defs_hpp_ - -#include -#include -#include -#include - -#include "framework/linalg/matrix_utils/matrix_defs.hpp" -#include "framework/types.hpp" -#include "framework/utils.hpp" - -namespace AER { -namespace Linalg { - -//------------------------------------------------------------------------------ -// Static Superoperator Matrices -//------------------------------------------------------------------------------ - -class SMatrix { -public: - // Single-qubit gates - const static cmatrix_t I; // name: "id" - const static cmatrix_t X; // name: "x" - const static cmatrix_t Y; // name: "y" - const static cmatrix_t Z; // name: "z" - const static cmatrix_t H; // name: "h" - const static cmatrix_t S; // name: "s" - const static cmatrix_t SDG; // name: "sdg" - const static cmatrix_t T; // name: "t" - const static cmatrix_t TDG; // name: "tdg" - const static cmatrix_t SX; // name: "sx" - const static cmatrix_t SXDG;// name: "sxdg" - const static cmatrix_t X90; // name: "x90" - - // Two-qubit gates - const static cmatrix_t CX; // name: "cx" - const static cmatrix_t CY; // name: "cy" - const static cmatrix_t CZ; // name: "cz" - const static cmatrix_t SWAP; // name: "swap" - - // Identity Matrix - static cmatrix_t identity(size_t dim); - - // Single-qubit waltz gates - static cmatrix_t u1(double lam); - static cmatrix_t u2(double phi, double lam); - static cmatrix_t u3(double theta, double phi, double lam); - static cmatrix_t u4(double theta, double phi, double lam, double gamma); - - // Single-qubit rotation gates - static cmatrix_t r(double phi, double lam); - static cmatrix_t rx(double theta); - static cmatrix_t ry(double theta); - static cmatrix_t rz(double theta); - - // Two-qubit rotation gates - static cmatrix_t rxx(double theta); - static cmatrix_t ryy(double theta); - static cmatrix_t rzz(double theta); - static cmatrix_t rzx(double theta); // rotation around Tensor(X, Z) - - // Phase Gates - static cmatrix_t phase(double theta); - static cmatrix_t phase_diag(double theta); - static cmatrix_t cphase_diag(double theta); - static cmatrix_t cphase(double theta); - - // Controlled-single qubit gate - static cmatrix_t cu(double theta, double phi, double lam, double gamma); - - // Complex arguments are implemented by taking std::real - // of the input - static cmatrix_t u1(complex_t lam) { return phase(std::real(lam)); } - static cmatrix_t u2(complex_t phi, complex_t lam) { - return u2(std::real(phi), std::real(lam)); - } - static cmatrix_t u3(complex_t theta, complex_t phi, complex_t lam) { - return u3(std::real(theta), std::real(phi), std::real(lam)); - }; - static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - } - static cmatrix_t r(complex_t theta, complex_t phi) { - return r(std::real(theta), std::real(phi)); - } - static cmatrix_t rx(complex_t theta) { return rx(std::real(theta)); } - static cmatrix_t ry(complex_t theta) { return ry(std::real(theta)); } - static cmatrix_t rz(complex_t theta) { return rz(std::real(theta)); } - static cmatrix_t rxx(complex_t theta) { return rxx(std::real(theta)); } - static cmatrix_t ryy(complex_t theta) { return ryy(std::real(theta)); } - static cmatrix_t rzz(complex_t theta) { return rzz(std::real(theta)); } - static cmatrix_t rzx(complex_t theta) { return rzx(std::real(theta)); } - static cmatrix_t phase(complex_t theta) { return phase(std::real(theta)); } - static cmatrix_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } - static cmatrix_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cmatrix_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - } - - // Return superoperator matrix for reset instruction - // on specified dim statespace. - // The returned matrix is (dim * dim, dim * dim). - static cmatrix_t reset(size_t dim); - - // Return the matrix for a named matrix string - // Allowed names correspond to all the const static single-qubit - // and two-qubit gate members - static const cmatrix_t from_name(const std::string &name) { - return *label_map_.at(name); - } - - // Check if the input name string is allowed - static bool allowed_name(const std::string &name) { - return (label_map_.find(name) != label_map_.end()); - } - -private: - // Lookup table that returns a pointer to the static data member - const static stringmap_t label_map_; -}; - -//============================================================================== -// Implementations -//============================================================================== - -const cmatrix_t SMatrix::I = Utils::unitary_superop(Matrix::I); - -const cmatrix_t SMatrix::X = Utils::unitary_superop(Matrix::X); - -const cmatrix_t SMatrix::Y = Utils::unitary_superop(Matrix::Y); - -const cmatrix_t SMatrix::Z = Utils::unitary_superop(Matrix::Z); - -const cmatrix_t SMatrix::S = Utils::unitary_superop(Matrix::S); - -const cmatrix_t SMatrix::SDG = Utils::unitary_superop(Matrix::SDG); - -const cmatrix_t SMatrix::T = Utils::unitary_superop(Matrix::T); - -const cmatrix_t SMatrix::TDG = Utils::unitary_superop(Matrix::TDG); - -const cmatrix_t SMatrix::H = Utils::unitary_superop(Matrix::H); - -const cmatrix_t SMatrix::SX = Utils::unitary_superop(Matrix::SX); - -const cmatrix_t SMatrix::SXDG = Utils::unitary_superop(Matrix::SXDG); - -const cmatrix_t SMatrix::X90 = Utils::unitary_superop(Matrix::X90); - -const cmatrix_t SMatrix::CX = Utils::unitary_superop(Matrix::CX); - -const cmatrix_t SMatrix::CY = Utils::unitary_superop(Matrix::CY); - -const cmatrix_t SMatrix::CZ = Utils::unitary_superop(Matrix::CZ); - -const cmatrix_t SMatrix::SWAP = Utils::unitary_superop(Matrix::SWAP); - -// Lookup table -const stringmap_t SMatrix::label_map_ = { - {"id", &SMatrix::I}, {"x", &SMatrix::X}, {"y", &SMatrix::Y}, - {"z", &SMatrix::Z}, {"h", &SMatrix::H}, {"s", &SMatrix::S}, - {"sdg", &SMatrix::SDG}, {"t", &SMatrix::T}, {"tdg", &SMatrix::TDG}, - {"x90", &SMatrix::X90}, {"cx", &SMatrix::CX}, {"cy", &SMatrix::CY}, - {"cz", &SMatrix::CZ}, {"swap", &SMatrix::SWAP}, {"sx", &SMatrix::SX}, - {"sxdg", &SMatrix::SXDG}, {"delay", &SMatrix::I}}; - -cmatrix_t SMatrix::identity(size_t dim) { return Matrix::identity(dim * dim); } - -cmatrix_t SMatrix::u1(double lambda) { - return phase(lambda); -} - -cmatrix_t SMatrix::u2(double phi, double lambda) { - return Utils::tensor_product(Matrix::u2(-phi, -lambda), - Matrix::u2(phi, lambda)); -} - -cmatrix_t SMatrix::u3(double theta, double phi, double lambda) { - return Utils::tensor_product(Matrix::u3(theta, -phi, -lambda), - Matrix::u3(theta, phi, lambda)); -} - -cmatrix_t SMatrix::u4(double theta, double phi, double lambda, double gamma) { - return Utils::tensor_product(Matrix::u4(theta, -phi, -lambda, -gamma), - Matrix::u4(theta, phi, lambda, gamma)); -} - -cmatrix_t SMatrix::r(double theta, double phi) { - return Utils::tensor_product(Matrix::r(-theta, -phi), Matrix::r(theta, phi)); -} - -cmatrix_t SMatrix::rx(double theta) { - return Utils::tensor_product(Matrix::rx(-theta), Matrix::rx(theta)); -} - -cmatrix_t SMatrix::ry(double theta) { - return Utils::tensor_product(Matrix::ry(theta), Matrix::ry(theta)); -} - -cmatrix_t SMatrix::rz(double theta) { - return Utils::tensor_product(Matrix::rz(-theta), Matrix::rz(theta)); -} - -cmatrix_t SMatrix::rxx(double theta) { - return Utils::tensor_product(Matrix::rxx(-theta), Matrix::rxx(theta)); -} - -cmatrix_t SMatrix::ryy(double theta) { - return Utils::tensor_product(Matrix::ryy(-theta), Matrix::ryy(theta)); -} - -cmatrix_t SMatrix::rzz(double theta) { - return Utils::tensor_product(Matrix::rzz(-theta), Matrix::rzz(theta)); -} - -cmatrix_t SMatrix::rzx(double theta) { - return Utils::tensor_product(Matrix::rzx(-theta), Matrix::rzx(theta)); -} - -cmatrix_t SMatrix::cu(double theta, double phi, double lambda, double gamma) { - return Utils::tensor_product(Matrix::cu(theta, -phi, -lambda, -gamma), - Matrix::cu(theta, phi, lambda, gamma)); -} - -cmatrix_t SMatrix::phase(double theta) { - cmatrix_t mat(4, 4); - mat(0, 0) = {1., 0.}; - mat(1, 1) = std::exp(complex_t(0., theta)); - mat(2, 2) = std::exp(complex_t(0., -theta)); - mat(3, 3) = {1., 0.}; - return mat; -} - -cmatrix_t SMatrix::phase_diag(double theta) { - cmatrix_t mat(1, 4); - mat(0, 0) = {1., 0.}; - mat(0, 1) = std::exp(complex_t(0., theta)); - mat(0, 2) = std::exp(complex_t(0., -theta)); - mat(0, 3) = {1., 0.}; - return mat; -} - -cmatrix_t SMatrix::cphase(double theta) { - const auto exp_p = std::exp(complex_t(0., theta)); - const auto exp_m = std::exp(complex_t(0., -theta)); - cmatrix_t mat(16, 16); - mat(0, 0) = {1., 0.}; - mat(1, 1) = {1., 0.}; - mat(2, 2) = {1., 0.}; - mat(3, 3) = exp_p; - mat(4, 4) = {1., 0.}; - mat(5, 5) = {1., 0.}; - mat(6, 6) = {1., 0.}; - mat(7, 7) = exp_p; - mat(8, 8) = {1., 0.}; - mat(9, 9) = {1., 0.}; - mat(10, 10) = {1., 0.}; - mat(11, 11) = exp_p; - mat(12, 12) = exp_m; - mat(13, 13) = exp_m; - mat(14, 14) = exp_m; - mat(15, 15) = {1., 0.}; - return mat; -} - -cmatrix_t SMatrix::cphase_diag(double theta) { - const auto exp_p = std::exp(complex_t(0., theta)); - const auto exp_m = std::exp(complex_t(0., -theta)); - cmatrix_t mat(1, 16); - mat(0, 0) = {1., 0.}; - mat(0, 1) = {1., 0.}; - mat(0, 2) = {1., 0.}; - mat(0, 3) = exp_p; - mat(0, 4) = {1., 0.}; - mat(0, 5) = {1., 0.}; - mat(0, 6) = {1., 0.}; - mat(0, 7) = exp_p; - mat(0, 8) = {1., 0.}; - mat(0, 9) = {1., 0.}; - mat(0, 10) = {1., 0.}; - mat(0, 11) = exp_p; - mat(0, 12) = exp_m; - mat(0, 13) = exp_m; - mat(0, 14) = exp_m; - mat(0, 15) = {1., 0.}; - return mat; -} - -cmatrix_t SMatrix::reset(size_t dim) { - cmatrix_t mat(dim * dim, dim * dim); - for (size_t j = 0; j < dim; j++) { - mat(0, j * (dim + 1)) = 1.; - } - return mat; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/vmatrix_defs.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/vmatrix_defs.hpp deleted file mode 100755 index bc4e68c61..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/matrix_utils/vmatrix_defs.hpp +++ /dev/null @@ -1,375 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_matrix_utils_vmatrix_defs_hpp_ -#define _aer_framework_linalg_matrix_utils_vmatrix_defs_hpp_ - -#include -#include -#include -#include - -#include "framework/linalg/matrix_utils/matrix_defs.hpp" -#include "framework/types.hpp" -#include "framework/utils.hpp" - -namespace AER { -namespace Linalg { - -//------------------------------------------------------------------------------ -// Static column-vectorized matrices -//------------------------------------------------------------------------------ - -class VMatrix { -public: - // Single-qubit gates - const static cvector_t I; // name: "id" - const static cvector_t X; // name: "x" - const static cvector_t Y; // name: "y" - const static cvector_t Z; // name: "z" - const static cvector_t H; // name: "h" - const static cvector_t S; // name: "s" - const static cvector_t SDG; // name: "sdg" - const static cvector_t T; // name: "t" - const static cvector_t TDG; // name: "tdg" - const static cvector_t SX; // name: "sx" - const static cvector_t SXDG;// name: "sxdg" - const static cvector_t X90; // name: "x90" - - // Two-qubit gates - const static cvector_t CX; // name: "cx" - const static cvector_t CY; // name: "cy" - const static cvector_t CZ; // name: "cz" - const static cvector_t SWAP; // name: "swap" - - // Identity Matrix - static cvector_t identity(size_t dim); - - // Single-qubit waltz gates - static cvector_t u1(double lam); - static cvector_t u2(double phi, double lam); - static cvector_t u3(double theta, double phi, double lam); - static cvector_t u4(double theta, double phi, double lam, double gamma); - - // Single-qubit rotation gates - static cvector_t r(double phi, double lam); - static cvector_t rx(double theta); - static cvector_t ry(double theta); - static cvector_t rz(double theta); - static cvector_t rz_diag(double theta); // return the matrix diagonal - - // Two-qubit rotation gates - static cvector_t rxx(double theta); - static cvector_t ryy(double theta); - static cvector_t rzz(double theta); - static cvector_t rzx(double theta); // rotation around Tensor(X, Z) - static cvector_t rzz_diag(double theta); // return the matrix diagonal - - // Phase Gates - static cvector_t phase(double theta); - static cvector_t phase_diag(double theta); - static cvector_t cphase(double theta); - static cvector_t cphase_diag(double theta); - - // Controlled-single qubit gate - static cvector_t cu(double theta, double phi, double lam, double gamma); - - // Complex arguments are implemented by taking std::real - // of the input - static cvector_t u1(complex_t lam) { return phase(std::real(lam)); } - static cvector_t u2(complex_t phi, complex_t lam) { - return u2(std::real(phi), std::real(lam)); - } - static cvector_t u3(complex_t theta, complex_t phi, complex_t lam) { - return u3(std::real(theta), std::real(phi), std::real(lam)); - }; - static cvector_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - }; - static cvector_t r(complex_t theta, complex_t phi) { - return r(std::real(theta), std::real(phi)); - } - static cvector_t rx(complex_t theta) { return rx(std::real(theta)); } - static cvector_t ry(complex_t theta) { return ry(std::real(theta)); } - static cvector_t rz(complex_t theta) { return rz(std::real(theta)); } - static cvector_t rz_diag(complex_t theta) { return rz_diag(std::real(theta)); } - static cvector_t rxx(complex_t theta) { return rxx(std::real(theta)); } - static cvector_t ryy(complex_t theta) { return ryy(std::real(theta)); } - static cvector_t rzz(complex_t theta) { return rzz(std::real(theta)); } - static cvector_t rzz_diag(complex_t theta) { return rzz_diag(std::real(theta)); } - static cvector_t rzx(complex_t theta) { return rzx(std::real(theta)); } - static cvector_t phase(complex_t theta) { return phase(std::real(theta)); } - static cvector_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } - static cvector_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cvector_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cvector_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); - } - - // Return the matrix for a named matrix string - // Allowed names correspond to all the const static single-qubit - // and two-qubit gate members - static const cvector_t from_name(const std::string &name) { - return *label_map_.at(name); - } - - // Check if the input name string is allowed - static bool allowed_name(const std::string &name) { - return (label_map_.find(name) != label_map_.end()); - } - -private: - // Lookup table that returns a pointer to the static data member - const static stringmap_t label_map_; -}; - -//============================================================================== -// Implementations -//============================================================================== - -const cvector_t VMatrix::I = Utils::vectorize_matrix(Matrix::I); - -const cvector_t VMatrix::X = Utils::vectorize_matrix(Matrix::X); - -const cvector_t VMatrix::Y = Utils::vectorize_matrix(Matrix::Y); - -const cvector_t VMatrix::Z = Utils::vectorize_matrix(Matrix::Z); - -const cvector_t VMatrix::S = Utils::vectorize_matrix(Matrix::S); - -const cvector_t VMatrix::SDG = Utils::vectorize_matrix(Matrix::SDG); - -const cvector_t VMatrix::T = Utils::vectorize_matrix(Matrix::T); - -const cvector_t VMatrix::TDG = Utils::vectorize_matrix(Matrix::TDG); - -const cvector_t VMatrix::H = Utils::vectorize_matrix(Matrix::H); - -const cvector_t VMatrix::SX = Utils::vectorize_matrix(Matrix::SX); - -const cvector_t VMatrix::SXDG = Utils::vectorize_matrix(Matrix::SXDG); - -const cvector_t VMatrix::X90 = Utils::vectorize_matrix(Matrix::X90); - -const cvector_t VMatrix::CX = Utils::vectorize_matrix(Matrix::CX); - -const cvector_t VMatrix::CY = Utils::vectorize_matrix(Matrix::CY); - -const cvector_t VMatrix::CZ = Utils::vectorize_matrix(Matrix::CZ); - -const cvector_t VMatrix::SWAP = Utils::vectorize_matrix(Matrix::SWAP); - -// Lookup table -const stringmap_t VMatrix::label_map_ = { - {"id", &VMatrix::I}, {"x", &VMatrix::X}, {"y", &VMatrix::Y}, - {"z", &VMatrix::Z}, {"h", &VMatrix::H}, {"s", &VMatrix::S}, - {"sdg", &VMatrix::SDG}, {"t", &VMatrix::T}, {"tdg", &VMatrix::TDG}, - {"x90", &VMatrix::X90}, {"cx", &VMatrix::CX}, {"cy", &VMatrix::CY}, - {"cz", &VMatrix::CZ}, {"swap", &VMatrix::SWAP}, {"sx", &VMatrix::SX}, - {"sxdg", &VMatrix::SXDG}, {"delay", &VMatrix::I}}; - -cvector_t VMatrix::identity(size_t dim) { - cvector_t mat(dim * dim); - for (size_t j = 0; j < dim; j++) - mat[j + j * dim] = {1.0, 0.0}; - return mat; -} - -cvector_t VMatrix::u1(double lambda) { - return phase(lambda); -} - -cvector_t VMatrix::u2(double phi, double lambda) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - const complex_t invsqrt2(1. / std::sqrt(2), 0.); - mat[0 + 0 * 2] = invsqrt2; - mat[0 + 1 * 2] = -std::exp(i * lambda) * invsqrt2; - mat[1 + 0 * 2] = std::exp(i * phi) * invsqrt2; - mat[1 + 1 * 2] = std::exp(i * (phi + lambda)) * invsqrt2; - return mat; -} - -cvector_t VMatrix::u3(double theta, double phi, double lambda) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - mat[0 + 0 * 2] = std::cos(0.5 * theta); - mat[0 + 1 * 2] = -std::exp(i * lambda) * std::sin(0.5 * theta); - mat[1 + 0 * 2] = std::exp(i * phi) * std::sin(0.5 * theta); - mat[1 + 1 * 2] = std::exp(i * (phi + lambda)) * std::cos(0.5 * theta); - return mat; -} - -cvector_t VMatrix::u4(double theta, double phi, double lambda, double gamma) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - mat[0 + 0 * 2] = std::exp(i * gamma) * std::cos(0.5 * theta); - mat[0 + 1 * 2] = -std::exp(i * (lambda + gamma)) * std::sin(0.5 * theta); - mat[1 + 0 * 2] = std::exp(i * (phi + gamma)) * std::sin(0.5 * theta); - mat[1 + 1 * 2] = std::exp(i * (phi + lambda + gamma)) * std::cos(0.5 * theta); - return mat; -} - -cvector_t VMatrix::r(double theta, double phi) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - mat[0 + 0 * 2] = std::cos(0.5 * theta); - mat[0 + 1 * 2] = -i * std::exp(-i * phi) * std::sin(0.5 * theta); - mat[1 + 0 * 2] = -i * std::exp(i * phi) * std::sin(0.5 * theta); - mat[1 + 1 * 2] = std::cos(0.5 * theta); - return mat; -} - -cvector_t VMatrix::rx(double theta) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - mat[0 + 0 * 2] = std::cos(0.5 * theta); - mat[0 + 1 * 2] = -i * std::sin(0.5 * theta); - mat[1 + 0 * 2] = mat[0 + 1 * 2]; - mat[1 + 1 * 2] = mat[0 + 0 * 2]; - return mat; -} - -cvector_t VMatrix::ry(double theta) { - cvector_t mat(2 * 2); - mat[0 + 0 * 2] = std::cos(0.5 * theta); - mat[0 + 1 * 2] = -1.0 * std::sin(0.5 * theta); - mat[1 + 0 * 2] = -mat[0 + 1 * 2]; - mat[1 + 1 * 2] = mat[0 + 0 * 2]; - return mat; -} - -cvector_t VMatrix::rz(double theta) { - cvector_t mat(2 * 2); - const complex_t i(0., 1.); - mat[0 + 0 * 2] = std::exp(-i * 0.5 * theta); - mat[1 + 1 * 2] = std::exp(i * 0.5 * theta); - return mat; -} - -cvector_t VMatrix::rz_diag(double theta) { - cvector_t diag(2); - const complex_t i(0., 1.); - return cvector_t({std::exp(-i * 0.5 * theta), std::exp(i * 0.5 * theta)}); -} - -cvector_t VMatrix::rxx(double theta) { - cvector_t mat(4 * 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat[0 + 0 * 4] = cost; - mat[0 + 3 * 4] = -i * sint; - mat[1 + 1 * 4] = cost; - mat[1 + 2 * 4] = -i * sint; - mat[2 + 1 * 4] = -i * sint; - mat[2 + 2 * 4] = cost; - mat[3 + 0 * 4] = -i * sint; - mat[3 + 3 * 4] = cost; - return mat; -} - -cvector_t VMatrix::ryy(double theta) { - cvector_t mat(4 * 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat[0 + 0 * 4] = cost; - mat[0 + 3 * 4] = i * sint; - mat[1 + 1 * 4] = cost; - mat[1 + 2 * 4] = -i * sint; - mat[2 + 1 * 4] = -i * sint; - mat[2 + 2 * 4] = cost; - mat[3 + 0 * 4] = i * sint; - mat[3 + 3 * 4] = cost; - return mat; -} - -cvector_t VMatrix::rzz(double theta) { - cvector_t mat(4 * 4); - const complex_t i(0., 1.); - const complex_t exp_p = std::exp(i * 0.5 * theta); - const complex_t exp_m = std::exp(-i * 0.5 * theta); - mat[0 + 0 * 4] = exp_m; - mat[1 + 1 * 4] = exp_p; - mat[2 + 2 * 4] = exp_p; - mat[3 + 3 * 4] = exp_m; - return mat; -} - -cvector_t VMatrix::rzz_diag(double theta) { - const complex_t i(0., 1.); - const complex_t exp_p = std::exp(i * 0.5 * theta); - const complex_t exp_m = std::exp(-i * 0.5 * theta); - return cvector_t({exp_m, exp_p, exp_p, exp_m}); -} - -cvector_t VMatrix::rzx(double theta) { - cvector_t mat(4 * 4); - const complex_t i(0., 1.); - const double cost = std::cos(0.5 * theta); - const double sint = std::sin(0.5 * theta); - mat[0 + 0 * 4] = cost; - mat[0 + 2 * 4] = -i * sint; - mat[1 + 1 * 4] = cost; - mat[1 + 3 * 4] = i * sint; - mat[2 + 0 * 4] = -i * sint; - mat[2 + 2 * 4] = cost; - mat[3 + 1 * 4] = i * sint; - mat[3 + 3 * 4] = cost; - return mat; -} - -cvector_t VMatrix::cu(double theta, double phi, double lambda, double gamma) { - cvector_t mat(4 * 4); - const complex_t i(0., 1.); - mat[0 + 0 * 4] = 1; - mat[2 + 2 * 4] = 1; - mat[1 + 1 * 4] = std::exp(i * gamma) * std::cos(0.5 * theta); - mat[1 + 3 * 4] = -std::exp(i * (lambda + gamma)) * std::sin(0.5 * theta); - mat[3 + 1 * 4] = std::exp(i * (phi + gamma)) * std::sin(0.5 * theta); - mat[3 + 3 * 4] = std::exp(i * (phi + lambda + gamma)) * std::cos(0.5 * theta); - return mat; -} - -cvector_t VMatrix::phase(double theta) { - cvector_t mat(2 * 2); - mat[0] = 1; - mat[3] = std::exp(complex_t(0.0, theta)); - return mat; -} - -cvector_t VMatrix::phase_diag(double theta) { - return {{1, std::exp(complex_t(0.0, theta))}}; -} - -cvector_t VMatrix::cphase(double theta) { - cvector_t mat(4 * 4); - mat[0] = 1; - mat[5] = 1; - mat[10] = 1; - mat[15] = std::exp(complex_t(0.0, theta)); - return mat; -} - -cvector_t VMatrix::cphase_diag(double theta) { - return {{1, 1, 1, std::exp(complex_t(0.0, theta))}}; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/square.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/square.hpp deleted file mode 100755 index 6baae7054..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/square.hpp +++ /dev/null @@ -1,208 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_square_hpp_ -#define _aer_framework_linalg_square_hpp_ - -#include -#include -#include -#include -#include - -#include "framework/json.hpp" -#include "framework/matrix.hpp" -#include "framework/linalg/vector.hpp" -#include "framework/types.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -namespace AER { -namespace Linalg { - -// This defines functions 'square' for entrywise square of -// numeric types, and 'isquare' for inplace entywise square. - -//---------------------------------------------------------------------------- -// Entrywise square of std::array -//---------------------------------------------------------------------------- - -// Return entrywise square of a vector -template > -std::array square(const std::array& data) { - std::array result = data; - return isquare(result); -} - -// Return inplace entrywise square of a vector -template > -std::array& isquare(std::array& data) { - std::transform(data.begin(), data.end(), data.begin(), data.begin(), - std::multiplies()); - return data; -} - -//---------------------------------------------------------------------------- -// Entrywise square of std::vector -//---------------------------------------------------------------------------- - -// Return entrywise square of a vector -template > -std::vector square(const std::vector& data) { - std::vector result; - result.reserve(data.size()); - std::transform(data.begin(), data.end(), data.begin(), std::back_inserter(result), - std::multiplies()); - return result; -} - -// Return inplace entrywise square of a vector -template > -std::vector& isquare(std::vector& data) { - std::transform(data.begin(), data.end(), data.begin(), data.begin(), - std::multiplies()); - return data; -} - -//---------------------------------------------------------------------------- -// Entrywise square of std::map -//---------------------------------------------------------------------------- - -template > -std::map square(const std::map& data) { - std::map result; - for (const auto& pair : data) { - result[pair.first] = pair.second * pair.second; - } - return result; -} - -template > -std::map& isquare(std::map& data) { - for (auto& pair : data) { - pair.second *= pair.second; - } - return data; -} - -//---------------------------------------------------------------------------- -// Entrywise square of std::unordered_map -//---------------------------------------------------------------------------- - -template > -std::unordered_map square( - const std::unordered_map& data) { - std::unordered_map result; - for (const auto& pair : data) { - result[pair.first] = pair.second * pair.second; - } - return result; -} - -template > -std::unordered_map& isquare(std::unordered_map& data) { - for (auto& pair : data) { - pair.second *= pair.second; - } - return data; -} - -//---------------------------------------------------------------------------- -// Entrywise square of matrix -//---------------------------------------------------------------------------- - -template > -matrix& isquare(matrix& data) { - for (size_t j = 0; j < data.size(); j++) { - data[j] *= data[j]; - } - return data; -} - -template > -matrix square(const matrix& data) { - matrix result = data; - return isquare(result); -} - -//---------------------------------------------------------------------------- -// Entrywise square of AER::Vector -//---------------------------------------------------------------------------- - -template > -Vector& isquare(Vector& vec) { - std::for_each(vec.data(), vec.data() + vec.size(), [](T&val) { val *= val; }); - return vec; -} - -template > -Vector square(const Vector& vec) { - Vector ret(vec.size(), false); - std::transform(vec.data(), vec.data() + vec.size(), ret.data(), - [](const T&val) { return val * val; }); - return ret; -} - -//---------------------------------------------------------------------------- -// Entrywise square of JSON -//---------------------------------------------------------------------------- - -inline json_t& isquare(json_t& data) { - // Terminating case - if (data.is_number()) { - double val = data; - data = val * val; - return data; - } - // Recursive cases - if (data.is_array()) { - for (size_t pos = 0; pos < data.size(); pos++) { - isquare(data[pos]); - } - return data; - } - if (data.is_object()) { - for (auto it = data.begin(); it != data.end(); ++it) { - isquare(data[it.key()]); - } - return data; - } - throw std::invalid_argument("Input JSONs cannot be squared."); -} - -inline json_t square(const json_t& data) { - json_t result = data; - return isquare(result); -} - -//---------------------------------------------------------------------------- -// Square of general type -//---------------------------------------------------------------------------- - -template -T square(const T& data) { - return data * data; -} - -template -T& isquare(T& data) { - data *= data; - return data; -} - -//------------------------------------------------------------------------------ -} // end namespace Linalg -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/vector.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/vector.hpp deleted file mode 100755 index ab7e16307..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/vector.hpp +++ /dev/null @@ -1,408 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_vector_hpp -#define _aer_framework_linalg_vector_hpp - -#include -#include -#include - -#include "framework/linalg/enable_if_numeric.hpp" - -/******************************************************************************* - * - * Numeric Vector class - * - ******************************************************************************/ - -namespace AER { - -template T *malloc_array(size_t size) { - return reinterpret_cast(malloc(sizeof(T) * size)); -} - -template T *calloc_array(size_t size) { - return reinterpret_cast(calloc(size, sizeof(T))); -} - -template class Vector { - -public: - //----------------------------------------------------------------------- - // Constructors and Destructor - //----------------------------------------------------------------------- - - // Construct an empty vector - Vector() = default; - - // Construct a vector - // If `fill=True` the vector will be initialized with all values in zero - // if `fill=False` the vector entries will be in an indeterminate state - // and should have their values assigned before use. - Vector(size_t sz, bool fill = true); - - // Copy construct a vector - Vector(const Vector &other); - - // Move construct a vector - Vector(Vector &&other) noexcept; - - // Destructor - virtual ~Vector() { free(data_); } - - //----------------------------------------------------------------------- - // Assignment - //----------------------------------------------------------------------- - - // Copy assignment - Vector &operator=(const Vector &other); - - // Move assignment - Vector &operator=(Vector &&other) noexcept; - - // Copy and cast assignment - template Vector &operator=(const Vector &other); - - //----------------------------------------------------------------------- - // Buffer conversion - //----------------------------------------------------------------------- - - // Copy construct a vector from C-array buffer - static Vector copy_from_buffer(size_t sz, const T *buffer); - - // Move construct a vector rom C-array buffer - static Vector move_from_buffer(size_t sz, T *buffer); - - // Copy vector to a new C-array - T *copy_to_buffer() const; - - // Move vector to a C-array - T *move_to_buffer(); - - //----------------------------------------------------------------------- - // Element access - //----------------------------------------------------------------------- - - // Addressing elements by vector representation - T &operator[](size_t i) noexcept { return data_[i]; }; - const T &operator[](size_t i) const noexcept { return data_[i]; }; - - // Access the array data pointer - const T *data() const noexcept { return data_; } - T *data() noexcept { return data_; } - - //----------------------------------------------------------------------- - // Capacity - //----------------------------------------------------------------------- - - // Check if vector is size 0 - bool empty() const noexcept { return size_ == 0; } - - // Return the size of the vector - size_t size() const noexcept { return size_; }; - - //----------------------------------------------------------------------- - // Operations - //----------------------------------------------------------------------- - - // Fill array with constant value - void fill(const T &val); - - // Swap contents of two vectors - void swap(Vector &other); - - // Empty the vector to size size - void clear() noexcept; - - // Resize container - // Value of additional entries will depend on allocator type - void resize(size_t sz); - - //----------------------------------------------------------------------- - // Linear Algebra - //----------------------------------------------------------------------- - // TODO: replace these with BLAS implementations - - // Entry wise addition - Vector operator+(const Vector &other) const; - Vector &operator+=(const Vector &other); - - // Entry wise subtraction - Vector operator-(const Vector &other) const; - Vector &operator-=(const Vector &other); - - // Scalar multiplication - Vector operator*(const T &other) const; - Vector &operator*=(const T &other); - - // Scalar multiplication with casting - template > - Vector operator*(const Scalar &other) const { - operator*(T{other}); - } - template > - Vector &operator*=(const Scalar &other) { - operator*=(T{other}); - } - - // Scalar division - Vector operator/(const T &other) const; - Vector &operator/=(const T &other); - - // Scalar division with casting - template > - Vector operator/(const Scalar &other) const { - operator/(T{other}); - } - template > - Vector &operator/=(const Scalar &other) { - operator/=(T{other}); - } - -protected: - // Vector size - size_t size_ = 0; - - // Vector data pointer - T *data_ = nullptr; -}; - -/******************************************************************************* - * - * Vector class: methods - * - ******************************************************************************/ - -//----------------------------------------------------------------------- -// Constructors -//----------------------------------------------------------------------- - -template -Vector::Vector(size_t sz, bool fill) - : size_(sz), data_((fill) ? calloc_array(size_) : malloc_array(size_)) {} - -template -Vector::Vector(const Vector &other) - : size_(other.size_), data_(malloc_array(other.size_)) { - std::copy(other.data_, other.data_ + other.size_, data_); -} - -template -Vector::Vector(Vector &&other) noexcept - : size_(other.size_), data_(other.data_) { - other.data_ = nullptr; - other.size_ = 0; -} - -//----------------------------------------------------------------------- -// Assignment -//----------------------------------------------------------------------- - -template Vector &Vector::operator=(Vector &&other) noexcept { - free(data_); - size_ = other.size_; - data_ = other.data_; - other.data_ = nullptr; - other.size_ = 0; - return *this; -} - -template Vector &Vector::operator=(const Vector &other) { - if (size_ != other.size_) { - free(data_); - size_ = other.size_; - data_ = malloc_array(size_); - } - std::copy(other.data_, other.data_ + size_, data_); - return *this; -} - -template -template -inline Vector &Vector::operator=(const Vector &other) { - - if (size_ != other.size_) { - free(data_); - size_ = other.size_; - data_ = malloc_array(size_); - } - std::transform(other.data_, other.data_ + size_, data_, - [](const S &i) { return T{i}; }); - return *this; -} - -//----------------------------------------------------------------------- -// Buffer conversion -//----------------------------------------------------------------------- - -template -Vector Vector::copy_from_buffer(size_t sz, const T *buffer) { - Vector ret; - ret.size_ = sz; - ret.data_ = malloc_array(ret.size_); - std::copy(buffer, buffer + ret.size_, ret.data_); - return ret; -} - -template -Vector Vector::move_from_buffer(size_t sz, T *buffer) { - Vector ret; - ret.size_ = sz; - ret.data_ = buffer; - return ret; -} - -template T *Vector::copy_to_buffer() const { - T *buffer = malloc_array(size_); - std::copy(data_, data_ + size_, buffer); - return buffer; -} - -template T *Vector::move_to_buffer() { - T *buffer = data_; - data_ = nullptr; - size_ = 0; - return buffer; -} - -//----------------------------------------------------------------------- -// Operations -//----------------------------------------------------------------------- - -template void Vector::clear() noexcept { - free(data_); - size_ = 0; -} - -template void Vector::swap(Vector &other) { - std::swap(size_, other.size_); - std::swap(data_, other.data_); -} - -template void Vector::resize(size_t sz) { - if (size_ == sz) - return; - T *tmp = calloc_array(sz); - std::move(data_, data_ + size_, tmp); - free(data_); - size_ = sz; - data_ = tmp; -} - -template void Vector::fill(const T &val) { - std::fill(data_, data_ + size_, val); -} - -//----------------------------------------------------------------------- -// Linear Algebra -//----------------------------------------------------------------------- - -template -Vector Vector::operator+(const Vector &other) const { - if (size_ != other.size_) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - Vector result; - result.size_ = size_; - result.data_ = malloc_array(size_); - std::transform(data_, data_ + size_, other.data_, result.data_, - [](const T &a, const T &b) -> T { return a + b; }); - return result; -} - -template Vector &Vector::operator+=(const Vector &other) { - if (size_ != other.size_) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::transform(data_, data_ + size_, other.data_, data_, - [](const T &a, const T &b) -> T { return a + b; }); - return *this; -} - -template -Vector Vector::operator-(const Vector &other) const { - if (size_ != other.size_) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - Vector result; - result.size_ = size_; - result.data_ = malloc_array(size_); - std::transform(data_, data_ + size_, other.data_, result.data_, - [](const T &a, const T &b) -> T { return a - b; }); - return result; -} - -template Vector &Vector::operator-=(const Vector &other) { - if (size_ != other.size_) { - throw std::runtime_error("Cannot add two vectors of different sizes."); - } - std::transform(data_, data_ + size_, other.data_, data_, - [](const T &a, const T &b) -> T { return a - b; }); - return *this; -} - -template Vector Vector::operator*(const T &other) const { - Vector ret; - ret.size_ = size_; - ret.data_ = malloc_array(size_); - std::transform(data_, data_ + size_, ret.data_, - [&other](const T &a) -> T { return a * other; }); - return ret; -} - -template Vector &Vector::operator*=(const T &other) { - std::for_each(data_, data_ + size_, - [&other](T &a) { a *= other; }); - return *this; -} - -template Vector Vector::operator/(const T &other) const { - Vector ret; - ret.size_ = size_; - ret.data_ = malloc_array(size_); - std::transform(data_, data_ + size_, ret.data_, - [&other](const T &a) -> T { return a / other; }); - return ret; -} - -template Vector &Vector::operator/=(const T &other) { - std::for_each(data_, data_ + size_, [&other](T &a) { a /= other; }); - return *this; -} - - -//------------------------------------------------------------------------------ -} // end Namespace AER -//------------------------------------------------------------------------------ - -//----------------------------------------------------------------------- -// ostream -//----------------------------------------------------------------------- -template -std::ostream &operator<<(std::ostream &out, const AER::Vector &v) { - out << "["; - size_t last = v.size() - 1; - const auto &data = v.data(); - for (size_t i = 0; i < v.size(); ++i) { - out << data[i]; - if (i != last) - out << ", "; - } - out << "]"; - return out; -} - -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/linalg/vector_json.hpp b/quantum/plugins/ibm/aer/src/framework/linalg/vector_json.hpp deleted file mode 100755 index 8f3f8d2a6..000000000 --- a/quantum/plugins/ibm/aer/src/framework/linalg/vector_json.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_linalg_vector_json_hpp -#define _aer_framework_linalg_vector_json_hpp - -#include - -#include "framework/linalg/vector.hpp" - -namespace AER { -//------------------------------------------------------------------------------ -// Implementation: JSON Conversion -//------------------------------------------------------------------------------ - - -template void to_json(nlohmann::json &js, const Vector &vec) { - js = nlohmann::json(); - for (size_t i = 0; i < vec.size(); i++) { - js.push_back(vec[i]); - } -} - - -template void from_json(const nlohmann::json &js, Vector &vec) { - // Check JSON is an array - if(!js.is_array()) { - throw std::invalid_argument( - std::string("JSON: invalid Vector (not array).")); - } - // Check if JSON is empty - if(js.empty()) { - return; - } - - // Initialize empty vector of correct size - const size_t size = js.size(); - vec = Vector(size, false); - for (size_t i = 0; i < size; ++i) { - vec[i] = js[i].get(); - } -} - -//------------------------------------------------------------------------------ -} // end Namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/matrix.hpp b/quantum/plugins/ibm/aer/src/framework/matrix.hpp deleted file mode 100755 index 54a836595..000000000 --- a/quantum/plugins/ibm/aer/src/framework/matrix.hpp +++ /dev/null @@ -1,834 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -/* -Dependences: BLAS -Brief Discription: This is my Matrix class. It works only with real/complex -matrices and stores the entries in column-major-order. In column-major storage -the columns are stored one after the other. The linear offset p from the -beginning of the array to any given element A(i,j) can then be computed as: - p = j*Nrows+i -where Nrows is the number of rows in the matrix. Hence, one scrolls down -rows and moves to a new column once the last row is reached. More precisely, if -i wanted to know the i and j associtated with a given p then i would use - i=p %Nrows - j= floor(p/Nrows) - -Multiplication is done with the C wrapper of the fortran blas library. -*/ - -#ifndef _aer_framework_matrix_hpp -#define _aer_framework_matrix_hpp - -#include -#include -#include -#include - -#include "framework/blas_protos.hpp" -#include "framework/linalg/enable_if_numeric.hpp" - -/******************************************************************************* - * - * Matrix Class - * - ******************************************************************************/ - -template -T* malloc_array(size_t size) { - return reinterpret_cast(malloc(sizeof(T) * size)); -} - -template -T* calloc_array(size_t size) { - return reinterpret_cast(calloc(size, sizeof(T))); -} - - -template // define a class template -class matrix { - // friend functions get to use the private variables of the class as well as - // have different classes as inputs - template - friend std::ostream & - operator<<(std::ostream &output, - const matrix &A); // overloading << to output a matrix - template - friend std::istream & - operator>>(std::istream &input, - const matrix &A); // overloading >> to read in a matrix - - // Multiplication (does not catch an error of a S1 = real and S2 being - // complex) - template - friend matrix - operator*(const S2 &beta, - const matrix &A); // multiplication by a scalar beta*A - template - friend matrix - operator*(const matrix &A, - const S2 &beta); // multiplication by a scalar A*beta - // Single-Precison Matrix Multiplication - friend matrix - operator*(const matrix &A, - const matrix &B); // real matrix multiplication A*B - friend matrix> operator*( - const matrix> &A, - const matrix> &B); // complex matrix multplication A*B - friend matrix> - operator*(const matrix &A, - const matrix> - &B); // real-complex matrix multplication A*B - friend matrix> - operator*(const matrix> &A, - const matrix &B); // real-complex matrix multplication A*B - // Double-Precision Matrix Multiplication - friend matrix - operator*(const matrix &A, - const matrix &B); // real matrix multiplication A*B - friend matrix> - operator*(const matrix> &A, - const matrix> - &B); // complex matrix multplication A*B - friend matrix> - operator*(const matrix &A, - const matrix> - &B); // real-complex matrix multplication A*B - friend matrix> - operator*(const matrix> &A, - const matrix &B); // real-complex matrix multplication A*B - // Single-Precision Matrix-Vector Multiplication - friend std::vector operator*(const matrix &A, - const std::vector &v); - friend std::vector> - operator*(const matrix> &A, - const std::vector> &v); - // Double-Precision Matrix-Vector Multiplication - friend std::vector operator*(const matrix &A, - const std::vector &v); - friend std::vector> - operator*(const matrix> &A, - const std::vector> &v); - -public: - //----------------------------------------------------------------------- - // Constructors and Destructor - //----------------------------------------------------------------------- - - // Construct an empty matrix - matrix() = default; - - // Construct a matrix of specified size - // If `fill=True` the matrix will be initialized with all values in zero - // if `fill=False` the matrix entries will be in an indeterminant state - // and should have their values assigned before use. - matrix(size_t rows, size_t cols, bool fill = true); - - // Copy construct a matrix - matrix(const matrix &other); - - // Move construct a matrix - matrix(matrix&& other) noexcept; - - // Destructor - virtual ~matrix() { free(data_); } - - //----------------------------------------------------------------------- - // Assignment - //----------------------------------------------------------------------- - - // Copy assignment - matrix &operator=(const matrix &other); - - // Move assignment - matrix &operator=(matrix &&other) noexcept; - - // Copy and cast assignment - template - matrix &operator=(const matrix &other); - - //----------------------------------------------------------------------- - // Buffer conversion - //----------------------------------------------------------------------- - - // Copy construct a matrix from C-array buffer - // The buffer should have size = rows * cols. - static matrix copy_from_buffer(size_t rows, size_t cols, const T* buffer); - - // Move construct a matrix from C-array buffer - // The buffer should have size = rows * cols. - static matrix move_from_buffer(size_t rows, size_t cols, T* buffer); - - // Copy matrix to a new C-array - T* copy_to_buffer() const; - - // Move matrix to a C-array - T* move_to_buffer(); - - //----------------------------------------------------------------------- - // Element access - //----------------------------------------------------------------------- - - // Addressing elements by vector representation - T& operator[](size_t element); - const T& operator[](size_t element) const; - - // Addressing elements by matrix representation - T& operator()(size_t row, size_t col); - const T& operator()(size_t row, size_t col) const; - - // Access the array data pointer - const T* data() const noexcept { return data_; } - T* data() noexcept { return data_; } - - //----------------------------------------------------------------------- - // Other methods - //----------------------------------------------------------------------- - - // Return the size of the underlying array - size_t size() const { return size_; } - - // Return True if size == 0 - bool empty() const { return size_ == 0; } - - // Clear used memory - void clear(); - - // Fill with constant value - void fill(const T& val); - - // Resize the matrix and reset to zero if different size - void initialize(size_t row, size_t col); - - // Resize the matrix keeping current values - void resize(size_t row, size_t col); - // Addressing elements by row or column - std::vector row_index(size_t row) const; - std::vector col_index(size_t col) const; - - // overloading functions. - matrix operator+(const matrix &A); - matrix operator-(const matrix &A); - matrix operator+(const matrix &A) const; - matrix operator-(const matrix &A) const; - matrix &operator+=(const matrix &A); - matrix &operator-=(const matrix &A); - - //----------------------------------------------------------------------- - // Legacy methods - //----------------------------------------------------------------------- - - // Member Functions - size_t GetColumns() const; // gives the number of columns - size_t GetRows() const; // gives the number of rows - size_t GetLD() const; // gives the leading dimension -- number of rows - -protected: - size_t rows_ = 0, cols_ = 0, size_ = 0, LD_ = 0; - // rows_ and cols_ are the rows and columns of the matrix - // size_ = rows*colums dimensions of the vector representation - // LD is the leading dimeonsion and for Column major order is in general eqaul - // to rows - - // the ptr to the vector containing the matrix - T* data_ = nullptr; -}; - -/******************************************************************************* - * - * Matrix class: methods - * - ******************************************************************************/ - -//----------------------------------------------------------------------- -// Constructors -//----------------------------------------------------------------------- - -template -matrix::matrix(size_t rows, size_t cols, bool fill) - : rows_(rows), cols_(cols), size_(rows * cols), LD_(rows), - data_((fill) ? calloc_array(size_) : malloc_array(size_)) {} - -template -matrix::matrix(const matrix &other) : matrix(other.rows_, other.cols_, false) { - std::copy(other.data_, other.data_ + other.size_, data_); -} - -template -matrix::matrix(matrix&& other) noexcept - : rows_(other.rows_), cols_(other.cols_), size_(other.size_), LD_(rows_), - data_(other.data_) { - other.data_ = nullptr; -} - -//----------------------------------------------------------------------- -// Assignment -//----------------------------------------------------------------------- - -template -matrix& matrix::operator=(matrix&& other) noexcept { - free(data_); - rows_ = other.rows_; - cols_ = other.cols_; - size_ = rows_ * cols_; - LD_ = other.LD_; - data_ = other.data_; - other.data_ = nullptr; - return *this; -} - -template -matrix &matrix::operator=(const matrix &other) { - if (rows_ != other.rows_ || cols_ != other.cols_) { - // size delete re-construct - // the matrix - free(data_); - rows_ = other.rows_; - cols_ = other.cols_; - size_ = rows_ * cols_; - LD_ = other.LD_; - data_ = malloc_array(size_); - } - std::copy(other.data_, other.data_ + size_, data_); - return *this; -} - -template -template -inline matrix &matrix::operator=(const matrix &other) { - - if (rows_ != other.GetRows() || - cols_ != other.GetColumns()) { - free(data_); - rows_ = other.GetRows(); - cols_ = other.GetColumns(); - size_ = rows_ * cols_; - LD_ = other.GetLD(); - data_ = malloc_array(size_); - } - for (size_t p = 0; p < size_; p++) { - data_[p] = T(other[p]); - } - return *this; -} - -//----------------------------------------------------------------------- -// Buffer conversion -//----------------------------------------------------------------------- - -template -matrix matrix::copy_from_buffer(size_t rows, size_t cols, const T* buffer) { - matrix ret; - ret.size_ = rows * cols; - ret.rows_ = rows; - ret.cols_ = cols; - ret.LD_ = rows; - ret.data_ = calloc_array(ret.size_); - std::copy(buffer, buffer + ret.size_, ret.data_); - return ret; -} - -template -matrix matrix::move_from_buffer(size_t rows, size_t cols, T* buffer) { - matrix ret; - ret.size_ = rows * cols; - ret.rows_ = rows; - ret.cols_ = cols; - ret.LD_ = rows; - ret.data_ = buffer; - return ret; -} - -template -T* matrix::copy_to_buffer() const { - T* buffer = malloc_array(size_); - std::copy(data_, data_ + size_, buffer); - return buffer; -} - -template -T* matrix::move_to_buffer() { - T* buffer = data_; - data_ = nullptr; - size_ = 0; - rows_ = 0; - cols_ = 0; - return buffer; -} - -//----------------------------------------------------------------------- -// Element access -//----------------------------------------------------------------------- - -template -T& matrix::operator[](size_t p) { -#ifdef DEBUG - if (p >= size_) { - std::cerr - << "error: matrix class operator []: Matrix subscript out of bounds" - << std::endl; - exit(1); - } -#endif - return data_[p]; -} -template -const T& matrix::operator[](size_t p) const { -#ifdef DEBUG - if (p >= size_) { - std::cerr << "Error: matrix class operator [] const: Matrix subscript out " - "of bounds" - << std::endl; - exit(1); - } -#endif - return data_[p]; -} - -template -T& matrix::operator()(size_t i, size_t j) { -#ifdef DEBUG - if (i >= rows_ || j >= cols_) { - std::cerr - << "Error: matrix class operator (): Matrices subscript out of bounds" - << std::endl; - exit(1); - } -#endif - return data_[j * rows_ + i]; -} - -template -const T& matrix::operator()(size_t i, size_t j) const { -#ifdef DEBUG - if (i >= rows_ || j >= cols_) { - std::cerr << "Error: matrix class operator () const: Matrices subscript " - "out of bounds" - << std::endl; - exit(1); - } -#endif - return data_[j * rows_ + i]; -} - -template -void matrix::clear() { - if (!data_ || !size_) - return; - rows_ = cols_ = size_ = 0; - free(data_); -} - -template inline void matrix::initialize(size_t rows, size_t cols) { - if (rows_ != rows || cols_ != cols) { - free(data_); - rows_ = rows; - cols_ = cols; - size_ = rows_ * cols_; - LD_ = rows; - data_ = calloc_array(size_); - } -} - -template -void matrix::fill(const T& val) { - std::fill(data_, data_ + size_, val); -} - -template -void matrix::resize(size_t rows, size_t cols) { - if (rows_ == rows && cols_ == cols) - return; - size_ = rows * cols; - T *tempmat = malloc_array(size_); - for (size_t j = 0; j < cols; j++) - for (size_t i = 0; i < rows; i++) - if (i < rows_ && j < cols_) - tempmat[j * rows + i] = data_[j * rows_ + i]; - else - tempmat[j * rows + i] = 0.0; - free(data_); - LD_ = rows_ = rows; - cols_ = cols; - data_ = tempmat; -} - -// Addressing elements by row or column -template inline std::vector matrix::row_index(size_t row) const { -#ifdef DEBUG - if (row >= rows_) { - std::cerr << "Error: matrix class operator row_index out of bounds " - << row << " >= " << rows_ << std::endl; - exit(1); - } -#endif - std::vector ret; - ret.reserve(cols_); - for(size_t i = 0; i < cols_; i++) - ret.emplace_back(data_[i * rows_ + row]); - // Allow for Named Return Value Optimization (NRVO) by not using std::move - return ret; -} -template inline std::vector matrix::col_index(size_t col) const { -#ifdef DEBUG - if (col >= cols_) { - std::cerr << "Error: matrix class operator col_index out of bounds " - << col << " >= " << cols_ << std::endl; - exit(1); - } -#endif - std::vector ret; - ret.reserve(rows_); - // we want the elements for all rows i..rows_ and column col - for(size_t i = 0; i < rows_; i++) - ret.emplace_back(data_[col * rows_ + i]); - // Allow for Named Return Value Optimization (NRVO) by not using std::move - return ret; -} - -template inline size_t matrix::GetRows() const { - // returns the rows of the matrix - return rows_; -} -template inline size_t matrix::GetColumns() const { - // returns the colums of the matrix - return cols_; -} -template inline size_t matrix::GetLD() const { - // returns the leading dimension - return LD_; -} - -template inline matrix matrix::operator+(const matrix &A) { -// overloads the + for matrix addition, can this be more efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr - << "Error: matrix class operator +: Matrices are not the same size" - << std::endl; - exit(1); - } -#endif - matrix temp(rows_, cols_); - for (unsigned int p = 0; p < size_; p++) { - temp.data_[p] = data_[p] + A.data_[p]; - } - return temp; -} -template inline matrix matrix::operator-(const matrix &A) { -// overloads the - for matrix substraction, can this be more efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr - << "Error: matrix class operator -: Matrices are not the same size" - << std::endl; - exit(1); - } -#endif - matrix temp(rows_, cols_); - for (unsigned int p = 0; p < size_; p++) { - temp.data_[p] = data_[p] - A.data_[p]; - } - return temp; -} -template -inline matrix matrix::operator+(const matrix &A) const { -// overloads the + for matrix addition if it is a const matrix, can this be more -// efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr << "Error: matrix class operator + const: Matrices are not the " - "same size" - << std::endl; - exit(1); - } -#endif - matrix temp(rows_, cols_); - for (unsigned int p = 0; p < size_; p++) { - temp.data_[p] = data_[p] + A.data_[p]; - } - return temp; -} -template -inline matrix matrix::operator-(const matrix &A) const { -// overloads the - for matrix substraction, can this be more efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr << "Error: matrix class operator - const: Matrices are not the " - "same size" - << std::endl; - exit(1); - } -#endif - matrix temp(rows_, cols_); - for (unsigned int p = 0; p < size_; p++) { - temp.data_[p] = data_[p] - A.data_[p]; - } - return temp; -} -template inline matrix &matrix::operator+=(const matrix &A) { -// overloads the += for matrix addition and assignment, can this be more -// efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr - << "Error: matrix class operator +=: Matrices are not the same size" - << std::endl; - exit(1); - } -#endif - for (size_t p = 0; p < size_; p++) { - data_[p] += A.data_[p]; - } - return *this; -} -template inline matrix &matrix::operator-=(const matrix &A) { -// overloads the -= for matrix subtraction and assignement, can this be more -// efficient -#ifdef DEBUG - if (rows_ != A.rows_ || cols_ != A.cols_) { - std::cerr - << "Error: matrix class operator -=: Matrices are not the same size" - << std::endl; - exit(1); - } -#endif - for (size_t p = 0; p < size_; p++) { - data_[p] -= A.data_[p]; - } - return *this; -} - -/******************************************************************************* - * - * Matrix class: Friend Functions - * - ******************************************************************************/ -template -std::ostream &operator<<(std::ostream &out, const matrix &A) { - out << "["; - size_t last_row = A.rows_ - 1; - size_t last_col = A.cols_ - 1; - for (size_t i = 0; i < A.rows_; ++i) { - out << "["; - for (size_t j = 0; j < A.cols_; ++j) { - out << A.data_[i + A.rows_ * j]; - if (j != last_col) - out << ", "; - } - out << "]"; - if (i != last_row) - out << ", "; - } - out << "]"; - return out; -} - -template -std::istream &operator>>(std::istream &input, const matrix &A) { - // overloads the >> to read in a row into column format - for (size_t j = 0; j < A.cols_; j++) { - for (size_t i = 0; i < A.rows_; i++) { - input >> A.data_[j * A.rows_ + i]; - } - } - return input; -} -template -matrix operator*(const matrix &A, const S2 &beta) { - // overloads A*beta - size_t rows = A.rows_, cols = A.cols_; - matrix temp(rows, cols); - for (size_t j = 0; j < cols; j++) { - for (size_t i = 0; i < rows; i++) { - temp(i, j) = beta * A(i, j); - } - } - return temp; -} -template -matrix operator*(const S2 &beta, const matrix &A) { - // overloads beta*A - size_t rows = A.rows_, cols = A.cols_; - matrix temp(rows, cols); - for (size_t j = 0; j < cols; j++) { - for (size_t i = 0; i < rows; i++) { - temp(i, j) = beta * A(i, j); - } - } - return temp; -} - -// Operator overloading with BLAS functions -inline matrix operator*(const matrix &A, - const matrix &B) { - // overloads A*B for real matricies and uses the blas dgemm routine - // cblas_dgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix C(A.rows_, B.cols_); - double alpha = 1.0, beta = 0.0; - dgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, - // A.cols_, 1.0, A.data_, A.LD_, B.data_, B.LD_, 0.0, C.data_, C.LD_); - return C; -} -inline matrix operator*(const matrix &A, const matrix &B) { - // overloads A*B for real matricies and uses the blas sgemm routine - // cblas_sgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix C(A.rows_, B.cols_); - float alpha = 1.0, beta = 0.0; - sgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, - // A.cols_, 1.0, A.data_, A.LD_, B.data_, B.LD_, 0.0, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix> &A, - const matrix> &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_); - std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, - // A.cols_, &alpha, A.data_, A.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix> &A, - const matrix> &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_); - std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, - // A.cols_, &alpha, A.data_, A.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix &A, const matrix> &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_), Ac(A.rows_, A.cols_); - Ac = A; - std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, &alpha, Ac.data_, - &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, Ac.rows_, B.cols_, - // Ac.cols_, &alpha, Ac.data_, Ac.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix &A, const matrix> &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_), Ac(A.rows_, A.cols_); - Ac = A; - std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, &alpha, Ac.data_, - &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, Ac.rows_, B.cols_, - // Ac.cols_, &alpha, Ac.data_, Ac.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix> &A, const matrix &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_), Bc(B.rows_, B.cols_); - Bc = B; - std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, Bc.cols_, - // A.cols_, &alpha, A.data_, A.LD_, Bc.data_, Bc.LD_, &beta, C.data_, C.LD_); - return C; -} -inline matrix> -operator*(const matrix> &A, const matrix &B) { - // overloads A*B for complex matricies and uses the blas zgemm routine - // cblas_zgemm(CblasXMajor,op,op,N,M,K,alpha,A,LDA,B,LDB,beta,C,LDC) - // C-> alpha*op(A)*op(B) +beta C - matrix> C(A.rows_, B.cols_), Bc(B.rows_, B.cols_); - Bc = B; - std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); - // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, Bc.cols_, - // A.cols_, &alpha, A.data_, A.LD_, Bc.data_, Bc.LD_, &beta, C.data_, C.LD_); - return C; -} - -// Single-Precision Real -inline std::vector operator*(const matrix &A, - const std::vector &x) { - // overload A*v for complex matrixies and will used a blas function - std::vector y(A.rows_); - float alpha = 1.0, beta = 0.0; - const size_t incx = 1, incy = 1; - sgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); - return y; -} -// Double-Precision Real -inline std::vector operator*(const matrix &A, - const std::vector &x) { - // overload A*v for complex matrixies and will used a blas function - std::vector y(A.rows_); - double alpha = 1.0, beta = 0.0; - const size_t incx = 1, incy = 1; - dgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); - return y; -} -// Single-Precision Complex -inline std::vector> -operator*(const matrix> &A, - const std::vector> &x) { - // overload A*v for complex matrixies and will used a blas function - std::vector> y(A.rows_); - std::complex alpha = 1.0, beta = 0.0; - const size_t incx = 1, incy = 1; - cgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); - return y; -} -// Double-Precision Complex -inline std::vector> -operator*(const matrix> &A, - const std::vector> &x) { - // overload A*v for complex matrixies and will used a blas function - std::vector> y(A.rows_); - std::complex alpha = 1.0, beta = 0.0; - const size_t incx = 1, incy = 1; - zgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); - return y; -} - -//------------------------------------------------------------------------------ -// end _matrix_h_ -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/noise_utils.hpp b/quantum/plugins/ibm/aer/src/framework/noise_utils.hpp deleted file mode 100644 index eb3947fbd..000000000 --- a/quantum/plugins/ibm/aer/src/framework/noise_utils.hpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_noise_utils_hpp_ -#define _aer_noise_utils_hpp_ - -#include "framework/utils.hpp" - -namespace AER { -namespace Utils { - -//========================================================================= -// Noise Transformation Functions -//========================================================================= - -// Transform a superoperator matrix to a Choi matrix -template -matrix superop2choi(const matrix& superop, size_t dim); - -// Transform a superoperator matrix to a set of Kraus matrices -template -std::vector> superop2kraus(const matrix& superop, size_t dim, double threshold = 1e-10); - -// Transform a Choi matrix to a superoperator matrix -template -matrix choi2superop(const matrix& choi, size_t dim); - -// Transform a Choi matrix to a set of Kraus matrices -template -std::vector>> -choi2kraus(const matrix>& choi, size_t dim, double threshold = 1e-10); - -// Transform a set of Kraus matrices to a Choi matrix -template -matrix kraus2choi(const std::vector>& kraus, size_t dim); - -// Transform a set of Kraus matrices to a superoperator matrix -template -matrix kraus2superop(const std::vector>& kraus, size_t dim); - -// Reshuffle transformation -// Transforms a matrix with dimension (d0 * d1, d2 * d3) -// into a matrix with dimension (d3 * d1, d2 * d0) -// by transposition of bipartite indices -// M[(i, j), (k, l)] -> M[(i, j), (k, i)] -template -matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, size_t d3); - - -//========================================================================= -// Implementations -//========================================================================= - -template -matrix kraus2superop(const std::vector>& kraus, size_t dim) { - matrix superop(dim * dim, dim * dim); - for (const auto mat : kraus) { - superop += Utils::tensor_product(Utils::conjugate(mat), mat); - } - return superop; -} - -template -matrix kraus2choi(const std::vector>& kraus, size_t dim) { - return superop2choi(kraus2superop(kraus, dim), dim); -} - -template -matrix superop2choi(const matrix& superop, size_t dim) { - return reshuffle(superop, dim, dim, dim, dim); -} - -template -std::vector> superop2kraus(const matrix& superop, size_t dim, double threshold) { - return choi2kraus(superop2choi(superop, dim), dim, threshold); -} - -template -matrix choi2superop(const matrix& choi, size_t dim) { - return reshuffle(choi, dim, dim, dim, dim); -} - -template -std::vector>> -choi2kraus(const matrix>& choi, size_t dim, double threshold) { - size_t dim2 = dim * dim; - - std::vector evals; - matrix> evecs; - - eigensystem_hermitian(choi, evals, evecs); - - // Convert eigensystem to Kraus operators - std::vector>> kraus; - for (size_t i = 0; i < dim2; i++) { - // Eigenvalues sorted smallest to largest so we index from the back - const size_t idx = dim2 - 1 - i; - const T eval = evals[idx]; - if (eval > 0.0 && !Linalg::almost_equal(eval, 0.0, threshold)) { - std::complex coeff(std::sqrt(eval), 0.0); - matrix> kmat(dim, dim); - for (size_t col = 0; col < dim; col++) - for (size_t row = 0; row < dim; row++) { - kmat(row, col) = coeff * evecs(row + dim * col, idx); - } - kraus.push_back(kmat); - } - } - return kraus; -} - -template -matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, size_t d3) { - matrix ret(d1 * d3, d0 * d2); - for (size_t i0 = 0; i0 < d0; ++i0) - for (size_t i1 = 0; i1 < d1; ++i1) - for (size_t i2 = 0; i2 < d2; ++i2) - for (size_t i3 = 0; i3 < d3; ++i3) { - ret(d1 * i3 + i1, d0 * i2 + i0) = mat(d1 * i0 + i1, d3 * i2 + i3); - } - return ret; -} - -//------------------------------------------------------------------------- -} // end namespace Noise -//------------------------------------------------------------------------- -} // end namespace AER -//------------------------------------------------------------------------- -#endif \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/operations.hpp b/quantum/plugins/ibm/aer/src/framework/operations.hpp deleted file mode 100755 index 8069931a4..000000000 --- a/quantum/plugins/ibm/aer/src/framework/operations.hpp +++ /dev/null @@ -1,1415 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_operations_hpp_ -#define _aer_framework_operations_hpp_ - -#include -#include -#include -#include -#include - -#include "framework/types.hpp" -#include "framework/json_parser.hpp" -#include "framework/utils.hpp" -#include "framework/linalg/almost_equal.hpp" -#include "simulators/stabilizer/clifford.hpp" - -namespace AER { -namespace Operations { - -// Comparisons enum class used for Boolean function operation. -// these are used to compare two hexadecimal strings and return a bool -// for now we only have one comparison Equal, but others will be added -enum class RegComparison {Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual}; - -// Enum class for operation types -enum class OpType { - gate, measure, reset, bfunc, barrier, qerror_loc, snapshot, - matrix, diagonal_matrix, multiplexer, initialize, sim_op, nop, - // Noise instructions - kraus, superop, roerror, noise_switch, - // Save instructions - save_state, save_expval, save_expval_var, save_statevec, save_statevec_dict, - save_densmat, save_probs, save_probs_ket, save_amps, save_amps_sq, - save_stabilizer, save_clifford, save_unitary, save_mps, save_superop, - // Set instructions - set_statevec, set_densmat, set_unitary, set_superop, - set_stabilizer, set_mps, - // Control Flow - jump, mark -}; - -enum class DataSubType { - single, c_single, list, c_list, accum, c_accum, average, c_average -}; - -static const std::unordered_set SAVE_TYPES = { - OpType::save_state, OpType::save_expval, OpType::save_expval_var, - OpType::save_statevec, OpType::save_statevec_dict, - OpType::save_densmat, OpType::save_probs, OpType::save_probs_ket, - OpType::save_amps, OpType::save_amps_sq, OpType::save_stabilizer, - OpType::save_clifford, - OpType::save_unitary, OpType::save_mps, OpType::save_superop -}; - -inline std::ostream& operator<<(std::ostream& stream, const OpType& type) { - switch (type) { - case OpType::gate: - stream << "gate"; - break; - case OpType::measure: - stream << "measure"; - break; - case OpType::reset: - stream << "reset"; - break; - case OpType::bfunc: - stream << "bfunc"; - break; - case OpType::barrier: - stream << "barrier"; - break; - case OpType::save_state: - stream << "save_state"; - break; - case OpType::save_expval: - stream << "save_expval"; - break; - case OpType::save_expval_var: - stream << "save_expval_var"; - case OpType::save_statevec: - stream << "save_statevector"; - break; - case OpType::save_statevec_dict: - stream << "save_statevector_dict"; - break; - case OpType::save_mps: - stream << "save_matrix_product_state"; - break; - case OpType::save_densmat: - stream << "save_density_matrix"; - break; - case OpType::save_probs: - stream << "save_probabilities"; - break; - case OpType::save_probs_ket: - stream << "save_probabilities_dict"; - break; - case OpType::save_amps: - stream << "save_amplitudes"; - break; - case OpType::save_amps_sq: - stream << "save_amplitudes_sq"; - break; - case OpType::save_stabilizer: - stream << "save_stabilizer"; - break; - case OpType::save_clifford: - stream << "save_clifford"; - break; - case OpType::save_unitary: - stream << "save_unitary"; - break; - case OpType::save_superop: - stream << "save_superop"; - break; - case OpType::set_statevec: - stream << "set_statevector"; - break; - case OpType::set_densmat: - stream << "set_density_matrix"; - break; - case OpType::set_unitary: - stream << "set_unitary"; - break; - case OpType::set_superop: - stream << "set_superop"; - break; - case OpType::set_stabilizer: - stream << "set_stabilizer"; - break; - case OpType::set_mps: - stream << "set_matrix_product_state"; - break; - case OpType::snapshot: - stream << "snapshot"; - break; - case OpType::matrix: - stream << "unitary"; - break; - case OpType::diagonal_matrix: - stream << "diagonal"; - break; - case OpType::multiplexer: - stream << "multiplexer"; - break; - case OpType::kraus: - stream << "kraus"; - break; - case OpType::superop: - stream << "superop"; - break; - case OpType::roerror: - stream << "roerror"; - break; - case OpType::qerror_loc: - stream << "qerror_loc"; - break; - case OpType::noise_switch: - stream << "noise_switch"; - break; - case OpType::initialize: - stream << "initialize"; - break; - case OpType::sim_op: - stream << "sim_op"; - break; - case OpType::nop: - stream << "nop"; - break; - case OpType::mark: - stream << "mark"; - break; - case OpType::jump: - stream << "jump"; - break; - default: - stream << "unknown"; - } - return stream; -} - - -inline std::ostream& operator<<(std::ostream& stream, const DataSubType& subtype) { - switch (subtype) { - case DataSubType::single: - stream << "single"; - break; - case DataSubType::c_single: - stream << "c_single"; - break; - case DataSubType::list: - stream << "list"; - break; - case DataSubType::c_list: - stream << "c_list"; - break; - case DataSubType::accum: - stream << "accum"; - break; - case DataSubType::c_accum: - stream << "c_accum"; - break; - case DataSubType::average: - stream << "average"; - break; - case DataSubType::c_average: - stream << "c_average"; - break; - default: - stream << "unknown"; - } - return stream; -} - - -//------------------------------------------------------------------------------ -// Op Class -//------------------------------------------------------------------------------ - -struct Op { - // General Operations - OpType type; // operation type identifier - std::string name; // operation name - reg_t qubits; // qubits operation acts on - std::vector regs; // list of qubits for matrixes - std::vector params; // real or complex params for gates - std::vector int_params; // integer parameters - std::vector string_params; // used for snapshot label, and boolean functions - - // Conditional Operations - bool conditional = false; // is gate conditional gate - uint_t conditional_reg; // (opt) the (single) register location to look up for conditional - RegComparison bfunc; // (opt) boolean function relation - - // Measurement - reg_t memory; // (opt) register operation it acts on (measure) - reg_t registers; // (opt) register locations it acts on (measure, conditional) - - // Mat and Kraus - std::vector mats; - - // Readout error - std::vector probs; - - // Expvals - std::vector> expval_params; - - // Set states - Clifford::Clifford clifford; - mps_container_t mps; - - // Legacy Snapshots - DataSubType save_type = DataSubType::single; - using pauli_component_t = std::pair; // Pair (coeff, label_string) - using matrix_component_t = std::pair>>; // vector of Pair(qubits, matrix), combined with coefficient - std::vector params_expval_pauli; - std::vector params_expval_matrix; // note that diagonal matrices are stored as - // 1 x M row-matrices - // Projector vectors are stored as - // M x 1 column-matrices -}; - -inline std::ostream& operator<<(std::ostream& s, const Op& op) { - s << op.name << "["; - bool first = true; - for (size_t qubit: op.qubits) { - if (!first) s << ","; - s << qubit; - first = false; - } - s << "],["; - first = true; - for (reg_t reg: op.regs) { - if (!first) s << ","; - s << "["; - bool first0 = true; - for (size_t qubit: reg) { - if (!first0) s << ","; - s << qubit; - first0 = false; - } - s << "]"; - first = false; - } - s << "]"; - return s; -} - -//------------------------------------------------------------------------------ -// Error Checking -//------------------------------------------------------------------------------ - -// Raise an exception if name string is empty -inline void check_empty_name(const Op &op) { - if (op.name.empty()) - throw std::invalid_argument(R"(Invalid qobj instruction ("name" is empty).)"); -} - -// Raise an exception if qubits list is empty -inline void check_empty_qubits(const Op &op) { - if (op.qubits.empty()) - throw std::invalid_argument(R"(Invalid qobj ")" + op.name + - R"(" instruction ("qubits" is empty).)"); -} - -// Raise an exception if params is empty -inline void check_empty_params(const Op &op) { - if (op.params.empty()) - throw std::invalid_argument(R"(Invalid qobj ")" + op.name + - R"(" instruction ("params" is empty).)"); -} - -// Raise an exception if params is empty -inline void check_length_params(const Op &op, const size_t size) { - if (op.params.size() != size) - throw std::invalid_argument(R"(Invalid qobj ")" + op.name + - R"(" instruction ("params" is incorrect length).)"); -} - -// Raise an exception if qubits list contains duplications -inline void check_duplicate_qubits(const Op &op) { - auto cpy = op.qubits; - std::unique(cpy.begin(), cpy.end()); - if (cpy != op.qubits) - throw std::invalid_argument(R"(Invalid qobj ")" + op.name + - R"(" instruction ("qubits" are not unique).)"); -} - -//------------------------------------------------------------------------------ -// Generator functions -//------------------------------------------------------------------------------ - -inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, std::string label = "") { - Op op; - op.type = OpType::matrix; - op.name = "unitary"; - op.qubits = qubits; - op.mats = {mat}; - if (label != "") - op.string_params = {label}; - return op; -} - -inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat, std::string label = "") { - Op op; - op.type = OpType::matrix; - op.name = "unitary"; - op.qubits = qubits; - op.mats.resize(1); - op.mats[0] = std::move(mat); - if (label != "") - op.string_params = {label}; - return op; -} - -inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, std::string label = "") { - Op op; - op.type = OpType::diagonal_matrix; - op.name = "diagonal"; - op.qubits = qubits; - op.params = std::move(vec); - - if (label != "") - op.string_params = {label}; - - return op; -} - -inline Op make_superop(const reg_t &qubits, const cmatrix_t &mat) { - Op op; - op.type = OpType::superop; - op.name = "superop"; - op.qubits = qubits; - op.mats = {mat}; - return op; -} - -inline Op make_superop(const reg_t &qubits, cmatrix_t &&mat) { - Op op; - op.type = OpType::superop; - op.name = "superop"; - op.qubits = qubits; - op.mats.resize(1); - op.mats[0] = std::move(mat); - return op; -} - -inline Op make_kraus(const reg_t &qubits, const std::vector &mats) { - Op op; - op.type = OpType::kraus; - op.name = "kraus"; - op.qubits = qubits; - op.mats = mats; - return op; -} - -inline Op make_kraus(const reg_t &qubits, std::vector &&mats) { - Op op; - op.type = OpType::kraus; - op.name = "kraus"; - op.qubits = qubits; - op.mats = std::move(mats); - return op; -} - -inline Op make_roerror(const reg_t &memory, const std::vector &probs) { - Op op; - op.type = OpType::roerror; - op.name = "roerror"; - op.memory = memory; - op.probs = probs; - return op; -} - -inline Op make_roerror(const reg_t &memory, std::vector &&probs) { - Op op; - op.type = OpType::roerror; - op.name = "roerror"; - op.memory = memory; - op.probs = std::move(probs); - return op; -} - -template // real or complex numeric type -inline Op make_u1(uint_t qubit, T lam) { - Op op; - op.type = OpType::gate; - op.name = "u1"; - op.qubits = {qubit}; - op.params = {lam}; - op.string_params = {op.name}; - return op; -} - -template // real or complex numeric type -inline Op make_u2(uint_t qubit, T phi, T lam) { - Op op; - op.type = OpType::gate; - op.name = "u2"; - op.qubits = {qubit}; - op.params = {phi, lam}; - op.string_params = {op.name}; - return op; -} - -template // real or complex numeric type -inline Op make_u3(uint_t qubit, T theta, T phi, T lam) { - Op op; - op.type = OpType::gate; - op.name = "u3"; - op.qubits = {qubit}; - op.params = {theta, phi, lam}; - op.string_params = {op.name}; - return op; -} - -inline Op make_reset(const reg_t & qubits, uint_t state = 0) { - Op op; - op.type = OpType::reset; - op.name = "reset"; - op.qubits = qubits; - return op; -} - -inline Op make_multiplexer(const reg_t &qubits, - const std::vector &mats, - std::string label = "") { - - // Check matrices are N-qubit - auto dim = mats[0].GetRows(); - auto num_targets = static_cast(std::log2(dim)); - if (1ULL << num_targets != dim) { - throw std::invalid_argument("invalid multiplexer matrix dimension."); - } - // Check number of matrix compents is power of 2. - size_t num_mats = mats.size(); - auto num_controls = static_cast(std::log2(num_mats)); - if (1ULL << num_controls != num_mats) { - throw std::invalid_argument("invalid number of multiplexer matrices."); - } - if (num_controls == 0) { // mats.size() must be 1 - return make_unitary(qubits, mats[0]); - } - // Check number of targets and controls matches qubits - if (num_controls + num_targets != qubits.size()) { - throw std::invalid_argument("multiplexer qubits don't match parameters."); - } - // Check each matrix component is unitary and same size - for (const auto &mat : mats) { - if (!Utils::is_unitary(mat, 1e-7)) - throw std::invalid_argument("multiplexer matrix is not unitary."); - if (mat.GetRows() != dim) { - throw std::invalid_argument("multiplexer matrices are different size."); - } - } - // Get lists of controls and targets - reg_t controls(num_controls), targets(num_targets); - std::copy_n(qubits.begin(), num_targets, targets.begin()); - std::copy_n(qubits.begin() + num_targets, num_controls, controls.begin()); - - // Construct the Op - Op op; - op.type = OpType::multiplexer; - op.name = "multiplexer"; - op.qubits = qubits; - op.mats = mats; - op.regs = std::vector({controls, targets}); - if (label != "") - op.string_params = {label}; - - // Validate qubits are unique. - check_empty_qubits(op); - check_duplicate_qubits(op); - - return op; -} - -//------------------------------------------------------------------------------ -// JSON conversion -//------------------------------------------------------------------------------ - -// Main deserialization functions -template -Op input_to_op(const inputdata_t& input); // Partial TODO -json_t op_to_json(const Op &op); // Partial TODO - -inline void from_json(const json_t &js, Op &op) {op = input_to_op(js);} - -inline void to_json(json_t &js, const Op &op) { js = op_to_json(op);} - -void to_json(json_t &js, const DataSubType& type); - -// Standard operations -template -Op input_to_op_gate(const inputdata_t& input); -template -Op input_to_op_barrier(const inputdata_t& input); -template -Op input_to_op_measure(const inputdata_t& input); -template -Op input_to_op_reset(const inputdata_t& input); -template -Op input_to_op_bfunc(const inputdata_t& input); -template -Op input_to_op_initialize(const inputdata_t& input); -template -Op input_to_op_pauli(const inputdata_t& input); - -// Set state -template -Op input_to_op_set_vector(const inputdata_t& input, OpType op_type); - -template -Op input_to_op_set_matrix(const inputdata_t& input, OpType op_type); - -template -Op input_to_op_set_clifford(const inputdata_t& input, OpType op_type); - -template -Op input_to_op_set_mps(const inputdata_t& input, OpType op_type); - -// Save data -template -Op input_to_op_save_default(const inputdata_t& input, OpType op_type); -template -Op input_to_op_save_expval(const inputdata_t& input, bool variance); -template -Op input_to_op_save_amps(const inputdata_t& input, bool squared); - -// Snapshots -template -Op input_to_op_snapshot(const inputdata_t& input); -template -Op input_to_op_snapshot_default(const inputdata_t& input); -template -Op input_to_op_snapshot_matrix(const inputdata_t& input); -template -Op input_to_op_snapshot_pauli(const inputdata_t& input); - -// Control-Flow -template -Op input_to_op_jump(const inputdata_t& input); -template -Op input_to_op_mark(const inputdata_t& input); - -// Matrices -template -Op input_to_op_unitary(const inputdata_t& input); -template -Op input_to_op_diagonal(const inputdata_t& input); -template -Op input_to_op_superop(const inputdata_t& input); -template -Op input_to_op_multiplexer(const inputdata_t& input); -template -Op input_to_op_kraus(const inputdata_t& input); -template -Op input_to_op_noise_switch(const inputdata_t& input); -template -Op input_to_op_qerror_loc(const inputdata_t& input); - -// Classical bits -template -Op input_to_op_roerror(const inputdata_t& input); - -// Optional instruction parameters -enum class Allowed {Yes, No}; - -template -void add_conditional(const Allowed val, Op& op, const inputdata_t& input); - - -//------------------------------------------------------------------------------ -// Implementation: JSON deserialization -//------------------------------------------------------------------------------ - -// TODO: convert if-else to switch -template -Op input_to_op(const inputdata_t& input) { - // load operation identifier - std::string name; - Parser::get_value(name, "name", input); - // Barrier - if (name == "barrier") - return input_to_op_barrier(input); - // Measure & Reset - if (name == "measure") - return input_to_op_measure(input); - if (name == "reset") - return input_to_op_reset(input); - if (name == "initialize") - return input_to_op_initialize(input); - // Arbitrary matrix gates - if (name == "unitary") - return input_to_op_unitary(input); - if (name == "diagonal" || name == "diag") - return input_to_op_diagonal(input); - if (name == "superop") - return input_to_op_superop(input); - // Save - if (name == "save_state") - return input_to_op_save_default(input, OpType::save_state); - if (name == "save_expval") - return input_to_op_save_expval(input, false); - if (name == "save_expval_var") - return input_to_op_save_expval(input, true); - if (name == "save_statevector") - return input_to_op_save_default(input, OpType::save_statevec); - if (name == "save_statevector_dict") - return input_to_op_save_default(input, OpType::save_statevec_dict); - if (name == "save_stabilizer") - return input_to_op_save_default(input, OpType::save_stabilizer); - if (name == "save_clifford") - return input_to_op_save_default(input, OpType::save_clifford); - if (name == "save_unitary") - return input_to_op_save_default(input, OpType::save_unitary); - if (name == "save_superop") - return input_to_op_save_default(input, OpType::save_superop); - if (name == "save_density_matrix") - return input_to_op_save_default(input, OpType::save_densmat); - if (name == "save_probabilities") - return input_to_op_save_default(input, OpType::save_probs); - if (name == "save_matrix_product_state") - return input_to_op_save_default(input, OpType::save_mps); - if (name == "save_probabilities_dict") - return input_to_op_save_default(input, OpType::save_probs_ket); - if (name == "save_amplitudes") - return input_to_op_save_amps(input, false); - if (name == "save_amplitudes_sq") - return input_to_op_save_amps(input, true); - // Set - if (name == "set_statevector") - return input_to_op_set_vector(input, OpType::set_statevec); - if (name == "set_density_matrix") - return input_to_op_set_matrix(input, OpType::set_densmat); - if (name == "set_unitary") - return input_to_op_set_matrix(input, OpType::set_unitary); - if (name == "set_superop") - return input_to_op_set_matrix(input, OpType::set_superop); - if (name == "set_stabilizer") - return input_to_op_set_clifford(input, OpType::set_stabilizer); - if (name == "set_matrix_product_state") - return input_to_op_set_mps(input, OpType::set_mps); - - // Snapshot - if (name == "snapshot") - return input_to_op_snapshot(input); - // Bit functions - if (name == "bfunc") - return input_to_op_bfunc(input); - // Noise functions - if (name == "noise_switch") - return input_to_op_noise_switch(input); - if (name == "qerror_loc") - return input_to_op_qerror_loc(input); - if (name == "multiplexer") - return input_to_op_multiplexer(input); - if (name == "kraus") - return input_to_op_kraus(input); - if (name == "roerror") - return input_to_op_roerror(input); - if (name == "pauli") - return input_to_op_pauli(input); - - //Control-flow - if (name == "jump") - return input_to_op_jump(input); - if (name == "mark") - return input_to_op_mark(input); - // Default assume gate - return input_to_op_gate(input); -} - -json_t op_to_json(const Op &op) { - json_t ret; - ret["name"] = op.name; - if (!op.qubits.empty()) - ret["qubits"] = op.qubits; - if (!op.regs.empty()) - ret["regs"] = op.regs; - if (!op.params.empty()) - ret["params"] = op.params; - else if (!op.int_params.empty()) - ret["params"] = op.int_params; - if (op.conditional) - ret["conditional"] = op.conditional_reg; - if (!op.memory.empty()) - ret["memory"] = op.memory; - if (!op.registers.empty()) - ret["register"] = op.registers; - if (!op.mats.empty()) - ret["mats"] = op.mats; - return ret; -} - - -void to_json(json_t &js, const OpType& type) { - std::stringstream ss; - ss << type; - js = ss.str(); -} - - -void to_json(json_t &js, const DataSubType& subtype) { - std::stringstream ss; - ss << subtype; - js = ss.str(); -} - - -//------------------------------------------------------------------------------ -// Implementation: Gates, measure, reset deserialization -//------------------------------------------------------------------------------ - -template -void add_conditional(const Allowed allowed, Op& op, const inputdata_t& input) { - // Check conditional - if (Parser::check_key("conditional", input)) { - // If instruction isn't allow to be conditional throw an exception - if (allowed == Allowed::No) { - throw std::invalid_argument("Invalid instruction: \"" + op.name + "\" cannot be conditional."); - } - // If instruction is allowed to be conditional add parameters - Parser::get_value(op.conditional_reg, "conditional", input); - op.conditional = true; - } -} - -template -Op input_to_op_gate(const inputdata_t& input) { - Op op; - op.type = OpType::gate; - Parser::get_value(op.name, "name", input); - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.params, "params", input); - - // Check for optional label - // If label is not specified record the gate name as the label - std::string label; - Parser::get_value(label, "label", input); - if (label != "") - op.string_params = {label}; - else - op.string_params = {op.name}; - - // Conditional - add_conditional(Allowed::Yes, op, input); - - // Validation - check_empty_name(op); - check_empty_qubits(op); - check_duplicate_qubits(op); - if (op.name == "u1") - check_length_params(op, 1); - else if (op.name == "u2") - check_length_params(op, 2); - else if (op.name == "u3") - check_length_params(op, 3); - return op; -} - -template -Op input_to_op_qerror_loc(const inputdata_t& input) { - Op op; - op.type = OpType::qerror_loc; - Parser::get_value(op.name, "label", input); - Parser::get_value(op.qubits, "qubits", input); - add_conditional(Allowed::Yes, op, input); - return op; -} - -template -Op input_to_op_barrier(const inputdata_t &input) { - Op op; - op.type = OpType::barrier; - op.name = "barrier"; - Parser::get_value(op.qubits, "qubits", input); - // Check conditional - add_conditional(Allowed::No, op, input); - return op; -} - -template -Op input_to_op_measure(const inputdata_t& input) { - Op op; - op.type = OpType::measure; - op.name = "measure"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.memory, "memory", input); - Parser::get_value(op.registers, "register", input); - - // Conditional - add_conditional(Allowed::No, op, input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - if (op.memory.empty() == false && op.memory.size() != op.qubits.size()) { - throw std::invalid_argument(R"(Invalid measure operation: "memory" and "qubits" are different lengths.)"); - } - if (op.registers.empty() == false && op.registers.size() != op.qubits.size()) { - throw std::invalid_argument(R"(Invalid measure operation: "register" and "qubits" are different lengths.)"); - } - return op; -} - -template -Op input_to_op_reset(const inputdata_t& input) { - Op op; - op.type = OpType::reset; - op.name = "reset"; - Parser::get_value(op.qubits, "qubits", input); - - // Conditional - add_conditional(Allowed::No, op, input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - return op; -} - -template -Op input_to_op_initialize(const inputdata_t& input) { - Op op; - op.type = OpType::initialize; - op.name = "initialize"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.params, "params", input); - - // Conditional - add_conditional(Allowed::No, op, input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - check_length_params(op, 1ULL << op.qubits.size()); - return op; -} -template -Op input_to_op_pauli(const inputdata_t& input){ - Op op; - op.type = OpType::gate; - op.name = "pauli"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.string_params, "params", input); - - // Check for optional label - // If label is not specified record the gate name as the label - std::string label; - Parser::get_value(label, "label", input); - if (label != "") - op.string_params.push_back(label); - else - op.string_params.push_back(op.name); - - // Conditional - add_conditional(Allowed::No, op, input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - - return op; -} - -//------------------------------------------------------------------------------ -// Implementation: Boolean Functions -//------------------------------------------------------------------------------ -template -Op input_to_op_bfunc(const inputdata_t& input) { - Op op; - op.type = OpType::bfunc; - op.name = "bfunc"; - op.string_params.resize(2); - std::string relation; - Parser::get_value(op.string_params[0], "mask", input); // mask hexadecimal string - Parser::get_value(op.string_params[1], "val", input); // value hexadecimal string - Parser::get_value(relation, "relation", input); // relation string - // Load single register / memory bit for storing result - uint_t tmp; - if (Parser::get_value(tmp, "register", input)) { - op.registers.push_back(tmp); - } - if (Parser::get_value(tmp, "memory", input)) { - op.memory.push_back(tmp); - } - - // Format hex strings - Utils::format_hex_inplace(op.string_params[0]); - Utils::format_hex_inplace(op.string_params[1]); - - const stringmap_t comp_table({ - {"==", RegComparison::Equal}, - {"!=", RegComparison::NotEqual}, - {"<", RegComparison::Less}, - {"<=", RegComparison::LessEqual}, - {">", RegComparison::Greater}, - {">=", RegComparison::GreaterEqual}, - }); - - auto it = comp_table.find(relation); - if (it == comp_table.end()) { - std::stringstream msg; - msg << "Invalid bfunc relation string :\"" << it->first << "\"." << std::endl; - throw std::invalid_argument(msg.str()); - } else { - op.bfunc = it->second; - } - - // Conditional - add_conditional(Allowed::No, op, input); - - // Validation - if (op.registers.empty()) { - throw std::invalid_argument("Invalid measure operation: \"register\" is empty."); - } - return op; -} - -template -Op input_to_op_roerror(const inputdata_t& input) { - Op op; - op.type = OpType::roerror; - op.name = "roerror"; - Parser::get_value(op.memory, "memory", input); - Parser::get_value(op.registers, "register", input); - Parser::get_value(op.probs, "params", input); - // Conditional - add_conditional(Allowed::No, op, input); - return op; -} - -//------------------------------------------------------------------------------ -// Implementation: Matrix and Kraus deserialization -//------------------------------------------------------------------------------ -template -Op input_to_op_unitary(const inputdata_t& input) { - Op op; - op.type = OpType::matrix; - op.name = "unitary"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.mats, "params", input); - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - if (op.mats.size() != 1) { - throw std::invalid_argument("\"unitary\" params must be a single matrix."); - } - for (const auto &mat : op.mats) { - if (!Utils::is_unitary(mat, 1e-7)) { - throw std::invalid_argument("\"unitary\" matrix is not unitary."); - } - } - // Check for a label - std::string label; - Parser::get_value(label, "label", input); - op.string_params.push_back(label); - - // Conditional - add_conditional(Allowed::Yes, op, input); - return op; -} -template -Op input_to_op_diagonal(const inputdata_t& input) { - Op op; - op.type = OpType::diagonal_matrix; - op.name = "diagonal"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.params, "params", input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - if (op.params.size() != 1ULL << op.qubits.size()) { - throw std::invalid_argument("\"diagonal\" matrix is wrong size."); - } - for (const auto &val : op.params) { - if (!Linalg::almost_equal(std::abs(val), 1.0, 1e-7)) { - throw std::invalid_argument("\"diagonal\" matrix is not unitary."); - } - } - - // Check for a label - std::string label; - Parser::get_value(label, "label", input); - op.string_params.push_back(label); - - // Conditional - add_conditional(Allowed::Yes, op, input); - return op; -} -template -Op input_to_op_superop(const inputdata_t& input) { - // Warning: we don't check superoperator is valid! - Op op; - op.type = OpType::superop; - op.name = "superop"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.mats, "params", input); - // Check conditional - add_conditional(Allowed::Yes, op, input); - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - if (op.mats.size() != 1) { - throw std::invalid_argument("\"superop\" params must be a single matrix."); - } - return op; -} -template -Op input_to_op_multiplexer(const inputdata_t& input) { - // Parse parameters - reg_t qubits; - std::vector mats; - std::string label; - Parser::get_value(qubits, "qubits", input); - Parser::get_value(mats, "params", input); - Parser::get_value(label, "label", input); - // Construct op - auto op = make_multiplexer(qubits, mats, label); - // Conditional - add_conditional(Allowed::Yes, op, input); - return op; -} -template -Op input_to_op_kraus(const inputdata_t& input) { - Op op; - op.type = OpType::kraus; - op.name = "kraus"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.mats, "params", input); - - // Validation - check_empty_qubits(op); - check_duplicate_qubits(op); - // Conditional - add_conditional(Allowed::Yes, op, input); - return op; -} - -template -Op input_to_op_noise_switch(const inputdata_t& input) { - Op op; - op.type = OpType::noise_switch; - op.name = "noise_switch"; - Parser::get_value(op.params, "params", input); - // Conditional - add_conditional(Allowed::No, op, input); - return op; -} - -//------------------------------------------------------------------------------ -// Implementation: Set state -//------------------------------------------------------------------------------ -template -Op input_to_op_set_vector(const inputdata_t &input, OpType op_type) { - Op op; - op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.params = Parser::template get_list_elem>(params, 0); - Parser::get_value(op.name, "name", input); - Parser::get_value(op.qubits, "qubits", input); - add_conditional(Allowed::No, op, input); - return op; -} - -template -Op input_to_op_set_matrix(const inputdata_t &input, OpType op_type) { - Op op; - op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.mats.push_back(Parser::template get_list_elem(params, 0)); - Parser::get_value(op.name, "name", input); - Parser::get_value(op.qubits, "qubits", input); - add_conditional(Allowed::No, op, input); - return op; -} - -template -Op input_to_op_set_clifford(const inputdata_t &input, OpType op_type) { - Op op; - op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.clifford = Parser::template get_list_elem(params, 0); - Parser::get_value(op.name, "name", input); - Parser::get_value(op.qubits, "qubits", input); - add_conditional(Allowed::No, op, input); - return op; -} - -template -Op input_to_op_set_mps(const inputdata_t &input, OpType op_type) { - Op op; - op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.mps = Parser::template get_list_elem(params, 0); - - Parser::get_value(op.name, "name", input); - Parser::get_value(op.qubits, "qubits", input); - add_conditional(Allowed::No, op, input); - return op; -} - -//------------------------------------------------------------------------------ -// Implementation: Save data deserialization -//------------------------------------------------------------------------------ -template -Op input_to_op_save_default(const inputdata_t& input, OpType op_type) { - Op op; - op.type = op_type; - Parser::get_value(op.name, "name", input); - - // Get subtype - static const std::unordered_map subtypes { - {"single", DataSubType::single}, - {"c_single", DataSubType::c_single}, - {"average", DataSubType::average}, - {"c_average", DataSubType::c_average}, - {"list", DataSubType::list}, - {"c_list", DataSubType::c_list}, - {"accum", DataSubType::accum}, - {"c_accum", DataSubType::c_accum}, - }; - std::string subtype; - Parser::get_value(subtype, "snapshot_type", input); - auto subtype_it = subtypes.find(subtype); - if (subtype_it == subtypes.end()) { - throw std::runtime_error("Invalid data subtype \"" + subtype + - "\" in save data instruction."); - } - op.save_type = subtype_it->second; - - // Get data key - op.string_params.emplace_back(""); - Parser::get_value(op.string_params[0], "label", input); - - // Add optional qubits field - Parser::get_value(op.qubits, "qubits", input); - return op; -} -template -Op input_to_op_save_expval(const inputdata_t& input, bool variance) { - // Initialized default save instruction params - auto op_type = (variance) ? OpType::save_expval_var - : OpType::save_expval; - Op op = input_to_op_save_default(input, op_type); - - // Parse Pauli operator components - const auto threshold = 1e-12; // drop small components - // Get components - if (Parser::check_key("params", input) && Parser::is_array("params", input)) { - for (const auto &comp_ : Parser::get_value("params", input)) { - const auto& comp = Parser::get_as_list(comp_); - // Get complex coefficient - std::vector coeffs = Parser::template get_list_elem>(comp, 1); - if (std::abs(coeffs[0]) > threshold || std::abs(coeffs[1]) > threshold) { - std::string pauli = Parser::template get_list_elem(comp, 0); - if (pauli.size() != op.qubits.size()) { - throw std::invalid_argument(std::string("Invalid expectation value save instruction ") + - "(Pauli label does not match qubit number.)."); - } - op.expval_params.emplace_back(pauli, coeffs[0], coeffs[1]); - } - } - } else { - throw std::invalid_argument("Invalid save expectation value \"params\"."); - } - - // Check edge case of all coefficients being empty - // In this case the operator had all coefficients zero, or sufficiently close - // to zero that they were all truncated. - if (op.expval_params.empty()) { - std::string pauli(op.qubits.size(), 'I'); - op.expval_params.emplace_back(pauli, 0., 0.); - } - - return op; -} -template -Op input_to_op_save_amps(const inputdata_t& input, bool squared) { - // Initialized default save instruction params - auto op_type = (squared) ? OpType::save_amps_sq - : OpType::save_amps; - Op op = input_to_op_save_default(input, op_type); - Parser::get_value(op.int_params, "params", input); - return op; -} - -//------------------------------------------------------------------------------ -// Implementation: Snapshot deserialization -//------------------------------------------------------------------------------ -template -Op input_to_op_snapshot(const inputdata_t& input) { - std::string snapshot_type; - Parser::get_value(snapshot_type, "snapshot_type", input); // LEGACY: to remove in 0.3 - Parser::get_value(snapshot_type, "type", input); - if (snapshot_type.find("expectation_value_pauli") != std::string::npos) - return input_to_op_snapshot_pauli(input); - if (snapshot_type.find("expectation_value_matrix") != std::string::npos) - return input_to_op_snapshot_matrix(input); - // Default snapshot: has "type", "label", "qubits" - auto op = input_to_op_snapshot_default(input); - // Conditional - add_conditional(Allowed::No, op, input); - return op; -} - -template -Op input_to_op_snapshot_default(const inputdata_t& input) { - Op op; - op.type = OpType::snapshot; - Parser::get_value(op.name, "type", input); // LEGACY: to remove in 0.3 - Parser::get_value(op.name, "snapshot_type", input); - // If missing use "default" for label - op.string_params.emplace_back("default"); - Parser::get_value(op.string_params[0], "label", input); - // Add optional qubits field - Parser::get_value(op.qubits, "qubits", input); - // If qubits is not empty, check for duplicates - check_duplicate_qubits(op); - return op; -} - -template -Op input_to_op_snapshot_pauli(const inputdata_t& input) { - Op op = input_to_op_snapshot_default(input); - - const auto threshold = 1e-15; // drop small components - // Get components - if (Parser::check_key("params", input) && Parser::is_array("params", input)) { - for (const auto &comp_ : Parser::get_value("params", input)) { - // Check component is length-2 array - const auto& comp = Parser::get_as_list(comp_); - if (comp.size() != 2) - throw std::invalid_argument("Invalid Pauli expval params (param component " + - Parser::dump(comp) + " invalid)."); - // Get complex coefficient - complex_t coeff = Parser::template get_list_elem(comp, 0); - // If coefficient is above threshold, get the Pauli operator string - // This string may contain I, X, Y, Z - // qubits are stored as a list where position is qubit number: - // eq op.qubits = [a, b, c], a is qubit-0, b is qubit-1, c is qubit-2 - // Pauli string labels are stored in little-endian ordering: - // eg label = "CBA", A is the Pauli for qubit-0, B for qubit-1, C for qubit-2 - if (std::abs(coeff) > threshold) { - std::string pauli = Parser::template get_list_elem(comp, 1); - if (pauli.size() != op.qubits.size()) { - throw std::invalid_argument(std::string("Invalid Pauli expectation value snapshot ") + - "(Pauli label does not match qubit number.)."); - } - // make tuple and add to components - op.params_expval_pauli.emplace_back(coeff, pauli); - } // end if > threshold - } // end component loop - } else { - throw std::invalid_argument("Invalid Pauli expectation value value snapshot \"params\"."); - } - // Check edge case of all coefficients being empty - // In this case the operator had all coefficients zero, or sufficiently close - // to zero that they were all truncated. - if (op.params_expval_pauli.empty()) { - // Add a single identity op with zero coefficient - std::string pauli(op.qubits.size(), 'I'); - complex_t coeff(0); - op.params_expval_pauli.emplace_back(coeff, pauli); - } - - return op; -} - -template -Op input_to_op_snapshot_matrix(const inputdata_t& input) { - // Load default snapshot parameters - Op op = input_to_op_snapshot_default(input); - - const auto threshold = 1e-10; // drop small components - // Get matrix operator components - // TODO: fix repeated throw string - if (Parser::check_key("params", input) && Parser::is_array("params", input)) { - for (const auto &comp_ : Parser::get_value("params", input)) { - const auto& comp = Parser::get_as_list(comp_); - // Check component is length-2 array - if (comp.size() != 2) { - throw std::invalid_argument("Invalid matrix expval snapshot (param component " + - Parser::dump(comp) + " invalid)."); - } - // Get complex coefficient - complex_t coeff = Parser::template get_list_elem(comp, 0); - std::vector> mats; - if (std::abs(coeff) > threshold) { - const inputdata_t& comp_list = comp[1]; - if (!Parser::is_array(comp_list)) { - throw std::invalid_argument("Invalid matrix expval snapshot (param component " + - Parser::dump(comp) + " invalid)."); - } - for (const auto &subcomp_ : comp_list) { - const auto& subcomp = Parser::get_as_list(subcomp_); - if (subcomp.size() != 2) { - throw std::invalid_argument("Invalid matrix expval snapshot (param component " + - Parser::dump(comp) + " invalid)."); - } - reg_t comp_qubits = Parser::template get_list_elem(subcomp, 0); - cmatrix_t comp_matrix = Parser::template get_list_elem(subcomp, 1); - // Check qubits are ok - // TODO: check that qubits are in range from 0 to Num of Qubits - 1 for instr - std::unordered_set unique = {comp_qubits.begin(), comp_qubits.end()}; - if (unique.size() != comp_qubits.size()) { - throw std::invalid_argument("Invalid matrix expval snapshot (param component " + - Parser::dump(comp) + " invalid)."); - } - mats.emplace_back(comp_qubits, comp_matrix); - } - op.params_expval_matrix.emplace_back(coeff, mats); - } - } // end component loop - } else { - throw std::invalid_argument(std::string("Invalid matrix expectation value snapshot ") + - "(\"params\" field missing)."); - } - return op; -} - -template -Op input_to_op_jump(const inputdata_t &input) { - Op op; - op.type = OpType::jump; - op.name = "jump"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.string_params, "params", input); - if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid jump (\"params\" field missing).")); - - // Conditional - add_conditional(Allowed::Yes, op, input); - - return op; -} - -template -Op input_to_op_mark(const inputdata_t &input) { - Op op; - op.type = OpType::mark; - op.name = "mark"; - Parser::get_value(op.qubits, "qubits", input); - Parser::get_value(op.string_params, "params", input); - if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid mark (\"params\" field missing).")); - - // Conditional - add_conditional(Allowed::No, op, input); - - return op; -} - - -//------------------------------------------------------------------------------ -} // end namespace Operations -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/opset.hpp b/quantum/plugins/ibm/aer/src/framework/opset.hpp deleted file mode 100755 index 850b1e6bf..000000000 --- a/quantum/plugins/ibm/aer/src/framework/opset.hpp +++ /dev/null @@ -1,284 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_opset_hpp_ -#define _aer_framework_opset_hpp_ - -#include -#include "framework/operations.hpp" - -namespace AER { -namespace Operations { - -//========================================================================= -// OpSet Class -//========================================================================= - -// This class is used to store type information about a set of operations. -class OpSet { -private: - // Hash function so that we can use an enum class as a std::unordered_set - // key on older C++11 compilers like GCC 5. - struct EnumClassHash { - template size_t operator()(T t) const { - return static_cast(t); - } - }; - -public: - // Alias for set of OpTypes - using optypeset_t = std::unordered_set; - - // Public data members - optypeset_t optypes; // A set of op types - stringset_t gates; // A set of names for OpType::gates - stringset_t snapshots; // set of types for OpType::snapshot - - OpSet() = default; - - OpSet(const optypeset_t &_optypes, const stringset_t &_gates, - const stringset_t &_snapshots) - : optypes(_optypes), gates(_gates), snapshots(_snapshots) {} - - OpSet(optypeset_t &&_optypes, stringset_t &&_gates, stringset_t &&_snapshots) - : optypes(std::move(_optypes)), gates(std::move(_gates)), - snapshots(std::move(_snapshots)) {} - - OpSet(const std::vector &ops) { - for (const auto &op : ops) { - insert(op); - } - } - - //----------------------------------------------------------------------- - // Insert operations to the OpSet - //----------------------------------------------------------------------- - - // Add another opset to the current one - void insert(const OpSet &_opset); - - // Add additional op to the opset - void insert(const Op &_op); - - //----------------------------------------------------------------------- - // Check if operations are in the OpSet - //----------------------------------------------------------------------- - - // Return true if another OpSet is contained in the current OpSet - bool contains(const OpSet &_opset) const; - - // Return true if an all operations are contained in the current OpSet - bool contains(const std::vector &_ops) const; - - // Return true if an operation is contained in the current OpSet - bool contains(const Op &_op) const; - - // Return true if all operation types are contained in the current OpSet - bool contains(const optypeset_t &_optypes) const; - - // Return true if an operation type is contained in the current OpSet - bool contains(const OpType &_optype) const; - - // Return true if all gates are contained in the current OpSet - bool contains_gates(const stringset_t &_gates) const; - - // Return true if gate is contained in the current OpSet - bool contains_gates(const std::string &_gate) const; - - // Return true if all snapshots are contained in the current OpSet - bool contains_snapshots(const stringset_t &_snapshots) const; - - // Return true if snapshot is contained in the current OpSet - bool contains_snapshots(const std::string &_snapshot) const; - - //----------------------------------------------------------------------- - // Return set difference with another OpSet - //----------------------------------------------------------------------- - - // Return an OpSet of all ops in another opset not contained in the OpSet - OpSet difference(const OpSet &_opset) const; - - // Return an Opset of all ops in a vector not contained in the OpSet - OpSet difference(const std::vector &_ops) const; - - // Return a set of all optypes in set not contained in the OpSet - optypeset_t difference(const optypeset_t &_optypes) const; - - // Return a set of all gates in a set not contained in the OpSet - stringset_t difference_gates(const stringset_t &_gates) const; - - // Return a set of all snapshots in a set not contained in the OpSet - stringset_t difference_snapshots(const stringset_t &_snapshots) const; - - // Return the difference between two unordered sets - template - static std::unordered_set - unorderedset_difference(const std::unordered_set &first, - const std::unordered_set &second); -}; - -//------------------------------------------------------------------------------ -// OpSet class methods -//------------------------------------------------------------------------------ - -void OpSet::insert(const Op &op) { - optypes.insert(op.type); - if (op.type == OpType::gate) - gates.insert(op.name); - else if (op.type == OpType::snapshot) - snapshots.insert(op.name); -} - -void OpSet::insert(const OpSet &opset) { - optypes.insert(opset.optypes.begin(), opset.optypes.end()); - gates.insert(opset.gates.begin(), opset.gates.end()); - snapshots.insert(opset.snapshots.begin(), opset.snapshots.end()); -} - -bool OpSet::contains(const OpSet &_opset) const { - return (contains(_opset.optypes) && contains_gates(_opset.gates) && - contains_snapshots(_opset.snapshots)); -} - -bool OpSet::contains(const Op &_op) const { - if (contains(_op.type)) { - if (_op.type == OpType::gate) - return contains_gates(_op.name); - else if (_op.type == OpType::snapshot) - return contains_snapshots(_op.name); - return true; - } - return false; -} - -bool OpSet::contains(const std::vector &_ops) const { - for (const auto &op : _ops) { - if (!contains(op)) - return false; - } - return true; -} - -bool OpSet::contains(const OpType &_optype) const { - return optypes.count(_optype) == 1; -} - -bool OpSet::contains(const optypeset_t &_optypes) const { - for (const auto &optype : _optypes) { - if (!contains(optype)) - return false; - } - return true; -} - -bool OpSet::contains_gates(const std::string &_gate) const { - return gates.count(_gate) == 1; -} - -bool OpSet::contains_gates(const stringset_t &_gates) const { - for (const auto &gate : _gates) { - if (!contains_gates(gate)) - return false; - } - return true; -} - -bool OpSet::contains_snapshots(const std::string &_snapshot) const { - return snapshots.count(_snapshot) == 1; -} - -bool OpSet::contains_snapshots(const stringset_t &_snapshots) const { - for (const auto &snapshot : _snapshots) { - if (!contains_snapshots(snapshot)) - return false; - } - return true; -} - -//----------------------------------------------------------------------- -// Return set difference with another OpSet -//----------------------------------------------------------------------- - -// Return an OpSet of all ops in another opset not contained in the OpSet -OpSet OpSet::difference(const OpSet &_opset) const { - OpSet ret; - ret.optypes = difference(_opset.optypes); - ret.gates = difference_gates(_opset.gates); - ret.snapshots = difference_snapshots(_opset.snapshots); - return ret; -} - -// Return a set of all optypes in set not contained in the OpSet -OpSet::optypeset_t OpSet::difference(const optypeset_t &_optypes) const { - return unorderedset_difference(optypes, _optypes); -} - -// Return a set of all gates in a set not contained in the OpSet -stringset_t OpSet::difference_gates(const stringset_t &_gates) const { - return unorderedset_difference(gates, _gates); -} - -// Return a set of all snapshots in a set not contained in the OpSet -stringset_t OpSet::difference_snapshots(const stringset_t &_snapshots) const { - return unorderedset_difference(snapshots, _snapshots); -} - -template -std::unordered_set -OpSet::unorderedset_difference(const std::unordered_set &first, - const std::unordered_set &second) { - std::unordered_set ret; - for (const auto &item : second) { - if (first.count(item) == 0) { - ret.insert(item); - } - } - return ret; -} - -//------------------------------------------------------------------------------ -} // end namespace Operations -} // end namespace AER -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------- -// Ostream overload for opset -//------------------------------------------------------------------------- - -inline std::ostream &operator<<(std::ostream &out, - const AER::Operations::OpSet &opset) { - bool first = true; - out << "{"; - if (!opset.optypes.empty()) { - out << "\"instructions\": " << opset.optypes; - first = false; - } - if (!opset.gates.empty()) { - if (!first) - out << ", "; - out << "\"gates\": " << opset.gates; - first = false; - } - if (!opset.snapshots.empty()) { - if (!first) - out << ", "; - out << "\"snapshots\": " << opset.snapshots; - first = false; - } - out << "}"; - return out; -} - -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/pybind_basics.hpp b/quantum/plugins/ibm/aer/src/framework/pybind_basics.hpp deleted file mode 100755 index 9a86c5d40..000000000 --- a/quantum/plugins/ibm/aer/src/framework/pybind_basics.hpp +++ /dev/null @@ -1,205 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019, 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_pybind_basics_hpp_ -#define _aer_framework_pybind_basics_hpp_ - -#include -#include - -#include "framework/linalg/vector.hpp" -#include "framework/matrix.hpp" - -#include "framework/pybind_json.hpp" - -namespace AerToPy { - -//============================================================================ -// Pybind11 move conversion of basic types -//============================================================================ - -// Move an arbitrary object to Python by calling Pybind11 cast with move -// Template specialization is used with this function for adding custom -// conversion for other types -// NOTE: Can this function be replaced by overload py::cast for custom types? -template py::object to_python(T &&obj); - -// Move a matrix to Python via conversion to Numpy array -template py::object to_python(matrix &&obj); - -// Move a Vector to Python via conversion to Numpy array -template py::object to_python(AER::Vector &&obj); - -// Move a Vector to Python via recusivly calling to_python on elements -template py::object to_python(std::vector &&obj); - -// Move an Unordered string map to Python object by calling to_python on elements -template py::object to_python(std::unordered_map &&obj); - -// Move an Unordered string map into an existing Python dict -template -void add_to_python(py::dict &pydata, std::unordered_map &&obj); - - -// Template specialization for moving numeric std::vectors to Numpy arrays -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector> &&obj); -template <> py::object to_python(std::vector> &&obj); - -// Template specialization for JSON -// NOTE: this copies rather than moves -template <> py::object to_python(json_t &&obj); - -//------------------------------------------------------------------------------ -// Convert To Numpy Arrays -//------------------------------------------------------------------------------ - -// Convert a matrix to a 2D Numpy array in Fortan order -template -py::array_t to_numpy(matrix &&obj); - -// Convert a Vector to a 1D Numpy array -template -py::array_t to_numpy(AER::Vector &&obj); - -// Convert a vector to a 1D Numpy array -template -py::array_t to_numpy(std::vector &&obj); - -//============================================================================ -// Implementation -//============================================================================ - -//------------------------------------------------------------------------------ -// Basic Types -//------------------------------------------------------------------------------ - -template -py::object to_python(T &&obj) { - return py::cast(obj, py::return_value_policy::move); -} - -template <> -py::object to_python(json_t &&obj) { - py::object pydata; - from_json(obj, pydata); - return pydata; -} - -template -py::object to_python(std::unordered_map &&obj) { - py::dict pydata; - add_to_python(pydata, std::move(obj)); - return std::move(pydata); -} - -template -void add_to_python(py::dict &pydata, std::unordered_map &&obj) { - for(auto& elt : obj) { - pydata[elt.first.data()] = to_python(std::move(elt.second)); - } -} - -template -py::object to_python(std::vector &&obj) { - py::list pydata; - for(auto& elt : obj) { - pydata.append(to_python(std::move(elt))); - } - return std::move(pydata); -} - -template -py::object to_python(matrix &&obj) { - return to_numpy(std::move(obj)); -} - -template -py::object to_python(AER::Vector &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector> &&obj) { - return to_numpy(std::move(obj)); -} - -template <> -py::object to_python(std::vector> &&obj) { - return to_numpy(std::move(obj)); -} - -//------------------------------------------------------------------------------ -// Array Types -//------------------------------------------------------------------------------ - -template -py::array_t to_numpy(matrix &&src) { - std::array shape {static_cast(src.GetRows()), - static_cast(src.GetColumns())}; - matrix* src_ptr = new matrix(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); - return py::array_t(shape, src_ptr->data(), capsule); -} - -template -py::array_t to_numpy(AER::Vector &&src) { - AER::Vector* src_ptr = new AER::Vector(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); - return py::array_t( - src_ptr->size(), // shape of array - src_ptr->data(), // c-style contiguous strides for vector - capsule // numpy array references this parent - ); -} - - -template -py::array_t to_numpy(std::vector &&src) { - std::vector* src_ptr = new std::vector(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); - return py::array_t( - src_ptr->size(), // shape of array - src_ptr->data(), // c-style contiguous strides for vector - capsule // numpy array references this parent - ); -} - -//------------------------------------------------------------------------------ -} // end namespace AerToPy -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/pybind_casts.hpp b/quantum/plugins/ibm/aer/src/framework/pybind_casts.hpp deleted file mode 100644 index de59f6de3..000000000 --- a/quantum/plugins/ibm/aer/src/framework/pybind_casts.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_pybind_casts_hpp_ -#define _aer_framework_pybind_casts_hpp_ - -#include "../simulators/stabilizer/clifford.hpp" - -namespace py = pybind11; - -namespace pybind11 { -namespace detail { -template struct type_caster>{ - using base = type_caster_base>; -public: - PYBIND11_TYPE_CASTER(matrix, _("matrix_t")); - // Conversion part 1 (Python->C++): - bool load(py::handle src, bool convert){ - // TODO: Check if make sense have to flavors of matrix: F-style and C-style - auto py_matrix = py::cast>(src); - auto c_order = py_matrix.attr("flags").attr("carray").template cast(); - if(py_matrix.ndim() != 2){ - throw std::invalid_argument(std::string("Python: invalid matrix (empty array).")); - } - size_t nrows = py_matrix.shape(0); - size_t ncols = py_matrix.shape(1); - // Matrix looks ok, now we parse it - auto raw_mat = py_matrix.template unchecked<2>(); - if(c_order){ - value = matrix(nrows, ncols, false); - for (size_t r = 0; r < nrows; r++) { - for (size_t c = 0; c < ncols; c++) { - value(r, c) = raw_mat(r, c); - } - } - } else { - value = matrix::copy_from_buffer(nrows, ncols, static_cast(py_matrix.request().ptr)); - } - return true; - } - // Conversion part 2 (C++ -> Python): - static py::handle cast(matrix, py::return_value_policy policy, py::handle parent){ - throw std::runtime_error("Casting from matrix to python not supported."); - } -}; - -template <> struct type_caster{ - using base = type_caster_base; -public: - PYBIND11_TYPE_CASTER(Clifford::Clifford, _("clifford")); - // Conversion part 1 (Python->C++): - bool load(py::handle src, bool convert){ - Clifford::build_from(src, value); - return true; - } - // Conversion part 2 (C++ -> Python): - static py::handle cast(Clifford::Clifford, py::return_value_policy policy, py::handle parent){ - throw std::runtime_error("Casting from Clifford to python not supported."); - } -}; -} -} - -#endif // _aer_framework_pybind_casts_hpp_ \ No newline at end of file diff --git a/quantum/plugins/ibm/aer/src/framework/pybind_json.hpp b/quantum/plugins/ibm/aer/src/framework/pybind_json.hpp deleted file mode 100755 index 4bcb9a7e6..000000000 --- a/quantum/plugins/ibm/aer/src/framework/pybind_json.hpp +++ /dev/null @@ -1,313 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_pybind_json_hpp_ -#define _aer_framework_pybind_json_hpp_ - -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below -#define snprintf _snprintf -#else -#undef snprintf -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "misc/warnings.hpp" -DISABLE_WARNING_PUSH -#include -#include -#include -#include -#include - -#include -DISABLE_WARNING_POP - -#include "framework/json.hpp" - -namespace py = pybind11; -namespace nl = nlohmann; -using namespace pybind11::literals; -using json_t = nlohmann::json; - -//------------------------------------------------------------------------------ -// Nlohman JSON <--> Python Conversion -//------------------------------------------------------------------------------ - -namespace std { - -/** - * Convert a python object to a json. - * @param js a json_t object to contain converted type. - * @param o is a python object to convert. - */ -void to_json(json_t &js, const py::handle &o); - -/** - * Create a python object from a json - * @param js a json_t object - * @param o is a reference to an existing (empty) python object - */ -void from_json(const json_t &js, py::object &o); - -} // end namespace std. - -//------------------------------------------------------------------------------ -// Python->JSON Conversion -//------------------------------------------------------------------------------ - -namespace JSON { - -/** - * Convert a numpy array to a json object - * @param arr is a numpy array - * @returns a json list (potentially of lists) - */ -template -json_t numpy_to_json(py::array_t arr); - -/** - * Convert a 1-d numpy array to a json object - * @param arr is a numpy array - * @returns a json list (potentially of lists) - */ -template -json_t numpy_to_json_1d(py::array_t arr); - -/** - * Convert a 2-d numpy array to a json object - * @param arr is a numpy array - * @returns a json list (potentially of lists) - */ -template -json_t numpy_to_json_2d(py::array_t arr); - -/** - * Convert a 3-d numpy array to a json object - * @param arr is a numpy array - * @returns a json list (potentially of lists) - */ -template -json_t numpy_to_json_3d(py::array_t arr); - -json_t iterable_to_json_list(const py::handle& obj); - -} //end namespace JSON - -/******************************************************************************* - * - * Implementations - * - ******************************************************************************/ - -//------------------------------------------------------------------------------ -// JSON Conversion -//------------------------------------------------------------------------------ - -template -json_t JSON::numpy_to_json_1d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 1) { - throw std::runtime_error("Number of dims must be 1"); - } - - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; - - std::vector tbr; // to be returned - for (size_t n0 = 0; n0 < D0; n0++) - tbr.push_back(ptr[n0]); - - return std::move(tbr); -} - -template -json_t JSON::numpy_to_json_2d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 2) { - throw std::runtime_error("Number of dims must be 2"); - } - - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; - size_t D1 = buf.shape[1]; - - std::vector > tbr; // to be returned - for (size_t n0 = 0; n0 < D0; n0++) { - std::vector tbr1; - for (size_t n1 = 0; n1 < D1; n1++) { - tbr1.push_back(ptr[n1 + D1*n0]); - } - tbr.push_back(tbr1); - } - - return std::move(tbr); - -} - -template -json_t JSON::numpy_to_json_3d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 3) { - throw std::runtime_error("Number of dims must be 3"); - } - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; - size_t D1 = buf.shape[1]; - size_t D2 = buf.shape[2]; - - // to be returned - std::vector > > tbr; - for (size_t n0 = 0; n0 < D0; n0++) { - std::vector > tbr1; - for (size_t n1 = 0; n1 < D1; n1++) { - std::vector tbr2; - for (size_t n2 = 0; n2 < D2; n2++) { - tbr2.push_back(ptr[n2 + D2*(n1 + D1*n0)]); - } - tbr1.push_back(tbr2); - } - tbr.push_back(tbr1); - } - - return std::move(tbr); - -} - -template -json_t JSON::numpy_to_json(py::array_t arr) { - py::buffer_info buf = arr.request(); - - if (buf.ndim == 1) { - return JSON::numpy_to_json_1d(arr); - } else if (buf.ndim == 2) { - return JSON::numpy_to_json_2d(arr); - } else if (buf.ndim == 3) { - return JSON::numpy_to_json_3d(arr); - } else { - throw std::runtime_error("Invalid number of dimensions!"); - } - json_t tbr; - return tbr; -} - -json_t JSON::iterable_to_json_list(const py::handle& obj){ - json_t js = nl::json::array(); - for (py::handle value: obj) { - js.push_back(value); - } - return js; -} - -void std::to_json(json_t &js, const py::handle &obj) { - static py::object PyNoiseModel = py::module::import("qiskit.providers.aer.noise.noise_model").attr("NoiseModel"); - static py::object PyQasmQobj = py::module::import("qiskit.qobj.qasm_qobj").attr("QasmQobj"); - if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj) || py::isinstance(obj)) { - js = JSON::iterable_to_json_list(obj); - } else if (py::isinstance(obj)) { - for (auto item : py::cast(obj)) { - js[item.first.cast()] = item.second; - } - } else if (py::isinstance >(obj)) { - js = JSON::numpy_to_json(obj.cast >()); - } else if (py::isinstance > >(obj)) { - js = JSON::numpy_to_json(obj.cast, py::array::c_style> >()); - } else if (obj.is_none()) { - return; - } else if (py::isinstance(obj, PyNoiseModel)){ - std::to_json(js, obj.attr("to_dict")()); - } else if (py::isinstance(obj, PyQasmQobj)){ - std::to_json(js, obj.attr("to_dict")()); - } else { - auto type_str = std::string(py::str(obj.get_type())); - if ( type_str == "" - || type_str == "" - || type_str == "" - || type_str == "" ) { - auto tmp = obj.cast>(); - js.push_back(tmp.real()); - js.push_back(tmp.imag()); - } else if ( type_str == "" - || type_str == "" - || type_str == "" - || type_str == "" ) { - js = obj.cast(); - } else if ( type_str == "" - || type_str == "" ) { - js = obj.cast(); - } else if ( py::isinstance(obj) ){ // last one to avoid intercepting numpy arrays, etc - js = JSON::iterable_to_json_list(obj); - } else { - throw std::runtime_error("to_json not implemented for this type of object: " + std::string(py::str(obj.get_type()))); - } - } -} - -void std::from_json(const json_t &js, py::object &o) { - if (js.is_boolean()) { - o = py::bool_(js.get()); - } else if (js.is_number()) { - if (js.is_number_float()) { - o = py::float_(js.get()); - } else if (js.is_number_unsigned()) { - o = py::int_(js.get()); - } else { - o = py::int_(js.get()); - } - } else if (js.is_string()) { - o = py::str(js.get()); - } else if (js.is_array()) { - std::vector obj(js.size()); - for (auto i = 0; i < js.size(); i++) - { - py::object tmp; - from_json(js[i], tmp); - obj[i] = tmp; - } - o = py::cast(obj); - } else if (js.is_object()) { - py::dict obj; - for (json_t::const_iterator it = js.cbegin(); it != js.cend(); ++it) - { - py::object tmp; - from_json(it.value(), tmp); - obj[py::str(it.key())] = tmp; - } - o = std::move(obj); - } else if (js.is_null()) { - o = py::none(); - } else { - throw std::runtime_error("from_json not implemented for this json::type: " + js.dump()); - } -} - -//------------------------------------------------------------------------------ - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/python_parser.hpp b/quantum/plugins/ibm/aer/src/framework/python_parser.hpp deleted file mode 100644 index e2867a8a0..000000000 --- a/quantum/plugins/ibm/aer/src/framework/python_parser.hpp +++ /dev/null @@ -1,154 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_python_parser_hpp_ -#define _aer_framework_python_parser_hpp_ - -#include "json.hpp" -#include "json_parser.hpp" -#include "pybind_json.hpp" - -namespace AER{ - -template <> -struct Parser { - Parser() = delete; - - static bool check_key(const std::string& key, const py::handle& po){ - if(py::isinstance(po)){ - return !py::cast(po)[key.c_str()].is_none(); - } - return py::hasattr(po, key.c_str()); - } - - static bool check_keys(const std::vector& keys, const py::handle& po) { - bool pass = true; - for (const auto &s : keys){ - pass &= check_key(s, po); - } - return pass; - } - - static py::object get_py_value(const std::string& key, const py::handle& po){ - if(py::isinstance(po)){ - return py::cast(po)[key.c_str()]; - } - return po.attr(key.c_str()); - } - - static bool get_value(py::object& var, const std::string& key, const py::handle& po) { - if(check_key(key, po)) { - var = get_py_value(key, po); - return true; - } else { - return false; - } - } - - template - static bool get_value(T &var, const std::string& key, const py::handle& po){ - if(check_key(key, po)) { - var = get_py_value(key, po).cast(); - return true; - } else { - return false; - } - } - - static void convert_to_json(json_t &var, const py::handle& po){ - if(py::hasattr(po, "to_dict")){ - std::to_json(var, po.attr("to_dict")()); - }else if(py::isinstance(po)){ - var = nl::json::array(); - for(auto item: po){ - json_t item_js; - convert_to_json(item_js, item); - var.push_back(item_js); - } - }else{ - std::to_json(var, po); - } - } - - static py::object get_value(const std::string& key, const py::handle& po){ - return get_py_value(key, po); - } - - static bool is_array(const py::handle& po){ - return py::isinstance(po) || py::isinstance(po); - } - - static bool is_array(const std::string& key, const py::handle& po) { - py::object the_list = get_py_value(key, po); - return is_array(the_list); - } - - static bool is_list_like(const py::handle& po){ - return is_array(po) || py::isinstance(po); - } - - static py::list get_as_list(const py::handle& po){ - if(!is_list_like(po)){ - throw std::runtime_error("Object is not list like!"); - } - return py::cast(po); - } - - static py::list get_list(const std::string& key, const py::handle& po){ - py::object the_list = get_py_value(key, po); - if(!is_array(the_list)){ - throw std::runtime_error("Object " + key + "is not a list!"); - } - return py::cast(the_list); - } - - static bool is_number(const py::handle& po){ - return py::isinstance(po) || py::isinstance(po); - } - - static bool is_number(const std::string& key, const py::handle& po) { - py::object key_po = get_py_value(key, po); - return is_number(key_po); - } - - template - static T get_list_elem(const py::list& po, unsigned int i){ - return py::cast(po[i]).cast(); - } - - template - static T get_list_elem(const py::handle& po, unsigned int i){ - auto py_list = get_as_list(po); - return get_list_elem(py_list, i); - } - - static std::string dump(const py::handle& po){ - json_t js; - convert_to_json(js, po); - return js.dump(); - } -}; - -template <> -bool Parser::get_value(json_t &var, const std::string& key, const py::handle& po){ - py::object ret_po; - auto success = get_value(ret_po, key, po); - if(success){ - convert_to_json(var, ret_po); - } - return success; -} -} - -#endif // _aer_framework_python_parser_hpp_ diff --git a/quantum/plugins/ibm/aer/src/framework/qobj.hpp b/quantum/plugins/ibm/aer/src/framework/qobj.hpp deleted file mode 100755 index 7eb7313a1..000000000 --- a/quantum/plugins/ibm/aer/src/framework/qobj.hpp +++ /dev/null @@ -1,189 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_qobj_hpp_ -#define _aer_framework_qobj_hpp_ - -#include -#include -#include -#include - -#include "framework/circuit.hpp" -#include "noise/noise_model.hpp" - -namespace AER { - -//============================================================================ -// Qobj data structure -//============================================================================ - -class Qobj { - public: - //---------------------------------------------------------------- - // Constructors - //---------------------------------------------------------------- - - // Default constructor and destructors - Qobj() = default; - virtual ~Qobj() = default; - - // Deserialization constructor - template - Qobj(const inputdata_t &input); - - //---------------------------------------------------------------- - // Data - //---------------------------------------------------------------- - std::string id; // qobj identifier passed to result - std::string type = "QASM"; // currently we only support QASM - std::vector circuits; // List of circuits - json_t header; // (optional) passed through to result - json_t config; // (optional) qobj level config data - Noise::NoiseModel noise_model; // (optional) noise model -}; - -//============================================================================ -// JSON initialization and deserialization -//============================================================================ - -// JSON deserialization -inline void from_json(const json_t &js, Qobj &qobj) { qobj = Qobj(js); } - -template -Qobj::Qobj(const inputdata_t &input) { - // Check required fields - if (Parser::get_value(id, "qobj_id", input) == false) { - throw std::invalid_argument(R"(Invalid qobj: no "qobj_id" field)"); - }; - Parser::get_value(type, "type", input); - if (type != "QASM") { - throw std::invalid_argument(R"(Invalid qobj: "type" != "QASM".)"); - }; - if (Parser::check_key("experiments", input) == false) { - throw std::invalid_argument(R"(Invalid qobj: no "experiments" field.)"); - } - - // Apply qubit truncation - bool truncation = true; - - // Parse config - if (Parser::get_value(config, "config", input)) { - // Check for truncation option - Parser::get_value(truncation, "enable_truncation", config); - - // Load noise model - if (Parser::get_value(noise_model, "noise_model", config)) { - // If noise model has non-local errors disable trunction - if (noise_model.has_nonlocal_quantum_errors()) { - truncation = false; - } - } - } else { - config = json_t::object(); - } - - // Parse header - if (!Parser::get_value(header, "header", input)) { - header = json_t::object(); - } - - // Check for fixed simulator seed - // If simulator seed is set, each experiment will be set to a fixed (but different) seed - // Otherwise a random seed will be chosen for each experiment - int_t seed = -1; - uint_t seed_shift = 0; - bool has_simulator_seed = Parser::get_value(seed, "seed_simulator", config); // config always json - const auto& circs = Parser::get_list("experiments", input); - const size_t num_circs = circs.size(); - - // Check if parameterized qobj - // It should be of the form - // [exp0_params, exp1_params, ...] - // where: - // expk_params = [((i, j), pars), ....] - // i is the instruction index in the experiment - // j is the param index in the instruction - // pars = [par0, par1, ...] is a list of different parameterizations - using pos_t = std::pair; - using exp_params_t = std::vector>>; - std::vector param_table; - Parser::get_value(param_table, "parameterizations", config); - - // Validate parameterizations for number of circuis - if (!param_table.empty() && param_table.size() != num_circs) { - throw std::invalid_argument( - R"(Invalid parameterized qobj: "parameterizations" length does not match number of circuits.)"); - } - - // Load circuits - for (size_t i=0; i(circs[i]), config, truncation); - // Non parameterized circuit - circuits.push_back(std::move(circuit)); - } else { - // Get base circuit from qobj without truncation - Circuit circuit(static_cast(circs[i]), config, false); - // Load different parameterizations of the initial circuit - const auto circ_params = param_table[i]; - const size_t num_params = circ_params[0].second.size(); - const size_t num_instr = circuit.ops.size(); - for (size_t j=0; j= num_instr) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction position out of range)"); - } - auto &op = param_circuit.ops[instr_pos]; - if (param_pos >= op.params.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction param position out of range)"); - } - if (j >= params.second.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: parameterization value out of range)"); - } - // Update the param - op.params[param_pos] = params.second[j]; - } - // Run truncation. - // TODO: Truncation should be performed and parameters should be resolved after it. - // However, parameters are associated with indices of instructions, which can be changed in truncation. - // Therefore, current implementation performs truncation for each parameter set. - if (truncation) - param_circuit.set_params(true); - circuits.push_back(std::move(param_circuit)); - } - } - } - // Override random seed with fixed seed if set - // We shift the seed for each successive experiment - // So that results aren't correlated between experiments - if (!has_simulator_seed) { - seed = circuits[0].seed; - } - for (auto& circuit : circuits) { - circuit.seed = seed + seed_shift; - seed_shift += 2113; // Shift the seed - } -} - -//------------------------------------------------------------------------------ -} // namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/data.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/data.hpp deleted file mode 100644 index 878c117af..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/data.hpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_hpp_ -#define _aer_framework_results_data_hpp_ - -// Data primatives -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" - -// Data Containers -#include "framework/results/data/mixins/data_creg.hpp" -#include "framework/results/data/mixins/data_rvalue.hpp" -#include "framework/results/data/mixins/data_rvector.hpp" -#include "framework/results/data/mixins/data_rdict.hpp" -#include "framework/results/data/mixins/data_cmatrix.hpp" -#include "framework/results/data/mixins/data_cvector.hpp" -#include "framework/results/data/mixins/data_cdict.hpp" -#include "framework/results/data/mixins/data_json.hpp" -#include "framework/results/data/mixins/data_mps.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct Data : public DataCreg, - public DataRValue, - public DataRVector, - public DataRDict, - public DataCVector, - public DataCMatrix, - public DataCDict, - public DataJSON, - public DataMPS { - - //---------------------------------------------------------------- - // Measurement data - //---------------------------------------------------------------- - - // Add outcome to count dictionary - void add_count(const std::string &outcome); - - // Add outcome to memory list - void add_memory(const std::string &outcome); - void add_memory(std::string &&outcome); - - //---------------------------------------------------------------- - // Add single data - //---------------------------------------------------------------- - template - void add_single(const T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_single(T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_single(T &&data, const std::string &outer_key, - const Args &... inner_keys); - - //---------------------------------------------------------------- - // Add list data - //---------------------------------------------------------------- - template - void add_list(const T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_list(T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_list(T &&data, const std::string &outer_key, - const Args &... inner_keys); - - //---------------------------------------------------------------- - // Add accum data - //---------------------------------------------------------------- - template - void add_accum(const T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_accum(T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_accum(T &&data, const std::string &outer_key, - const Args &... inner_keys); - - //---------------------------------------------------------------- - // Add average data - //---------------------------------------------------------------- - template - void add_average(const T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_average(T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add_average(T &&data, const std::string &outer_key, - const Args &... inner_keys); - - //---------------------------------------------------------------- - // Utility and config - //---------------------------------------------------------------- - - // Serialize engine data to JSON - json_t to_json(); - - // Combine stored data - Data &combine(Data &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -Data &Data::combine(Data &&other) { - DataRValue::combine(std::move(other)); - DataRVector::combine(std::move(other)); - DataRDict::combine(std::move(other)); - DataCVector::combine(std::move(other)); - DataCMatrix::combine(std::move(other)); - DataCDict::combine(std::move(other)); - DataJSON::combine(std::move(other)); - DataMPS::combine(std::move(other)); - DataCreg::combine(std::move(other)); - return *this; -} - -json_t Data::to_json() { - json_t result = json_t::object(); - DataRValue::add_to_json(result); - DataRVector::add_to_json(result); - DataRDict::add_to_json(result); - DataCVector::add_to_json(result); - DataCMatrix::add_to_json(result); - DataCDict::add_to_json(result); - DataJSON::add_to_json(result); - DataMPS::add_to_json(result); - DataCreg::add_to_json(result); - return result; -} - - -template -void Data::add_single(const T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_single(T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_single(T &&data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(std::move(data), outer_key, - inner_keys...); -} - -template -void Data::add_list(const T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_list(T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_list(T &&data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(std::move(data), outer_key, - inner_keys...); -} - -template -void Data::add_accum(const T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_accum(T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_accum(T &&data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(std::move(data), outer_key, - inner_keys...); -} - -template -void Data::add_average(const T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_average(T &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Data::add_average(T &&data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(std::move(data), outer_key, - inner_keys...); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/metadata.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/metadata.hpp deleted file mode 100644 index 969179ca3..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/metadata.hpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2018, 2019. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_metadata_hpp_ -#define _aer_framework_results_data_metadata_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/single_data.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct Metadata : public DataMap, - public DataMap, - public DataMap { - - //---------------------------------------------------------------- - // Add JSON metadata - //---------------------------------------------------------------- - template - void add(const json_t &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add(json_t &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add(json_t &&data, const std::string &outer_key, - const Args &... inner_keys); - - //---------------------------------------------------------------- - // Add general metadata - // - // These functions allow adding general data types via conversion - // to json_t. - //---------------------------------------------------------------- - template - void add(const T &data, const std::string &outer_key, - const Args &... inner_keys); - - template - void add(T &data, const std::string &outer_key, const Args &... inner_keys); - - template - void add(T &&data, const std::string &outer_key, const Args &... inner_keys); - - // Serialize engine data to JSON - json_t to_json(); - - // Combine stored data - Metadata &combine(Metadata &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -Metadata &Metadata::combine(Metadata &&other) { - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - return *this; -} - -json_t Metadata::to_json() { - json_t result = json_t::object(); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - return result; -} - -template -void Metadata::add(const T &data, const std::string &outer_key, - const Args &... inner_keys) { - json_t tmp = data; - DataMap::add( - std::move(tmp), outer_key, inner_keys...); -} - -template -void Metadata::add(T &data, const std::string &outer_key, - const Args &... inner_keys) { - json_t tmp = data; - DataMap::add( - std::move(tmp), outer_key, inner_keys...); -} - -template -void Metadata::add(T &&data, const std::string &outer_key, - const Args &... inner_keys) { - json_t tmp = data; - DataMap::add( - std::move(tmp), outer_key, inner_keys...); -} - -template -void Metadata::add(const json_t &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Metadata::add(json_t &data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add(data, outer_key, - inner_keys...); -} - -template -void Metadata::add(json_t &&data, const std::string &outer_key, - const Args &... inner_keys) { - DataMap::add( - std::move(data), outer_key, inner_keys...); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cdict.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cdict.hpp deleted file mode 100644 index 16d1e3b8d..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cdict.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_cdict_hpp_ -#define _aer_framework_results_data_cdict_hpp_ - -#include -#include - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataCDict : public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2> { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataCDict &combine(DataCDict &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataCDict &DataCDict::combine(DataCDict &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - return *this; -} - -void DataCDict::add_to_json(json_t &result) { - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cmatrix.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cmatrix.hpp deleted file mode 100644 index 0aa192060..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cmatrix.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_cmatrix_hpp_ -#define _aer_framework_results_data_cmatrix_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataCMatrix : - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2> { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataCMatrix &combine(DataCMatrix &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataCMatrix &DataCMatrix::combine(DataCMatrix &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - return *this; -} - -void DataCMatrix::add_to_json(json_t &result) { - - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_creg.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_creg.hpp deleted file mode 100644 index 73a68acb1..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_creg.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_creg_hpp_ -#define _aer_framework_results_data_creg_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataCreg : public DataMap, // Counts - public DataMap // Memory -{ - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataCreg &combine(DataCreg &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataCreg &DataCreg::combine(DataCreg &&other) { - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - return *this; -} - -void DataCreg::add_to_json(json_t &result) { - DataMap::add_to_json(result); - DataMap::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cvector.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cvector.hpp deleted file mode 100644 index cde3fd763..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_cvector.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_cvector_hpp_ -#define _aer_framework_results_data_cvector_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataCVector : public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2> { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataCVector &combine(DataCVector &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataCVector &DataCVector::combine(DataCVector &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - return *this; -} - -void DataCVector::add_to_json(json_t &result) { - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 2>::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_json.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_json.hpp deleted file mode 100644 index 01104c3a8..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_json.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_json_hpp_ -#define _aer_framework_results_data_json_hpp_ - -#include -#include - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataJSON : public DataMap, - public DataMap, - public DataMap, - public DataMap { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataJSON &combine(DataJSON &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataJSON &DataJSON::combine(DataJSON &&other) { - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - return *this; -} - -void DataJSON::add_to_json(json_t &result) { - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_mps.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_mps.hpp deleted file mode 100644 index 21e20619c..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_mps.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_mps_hpp_ -#define _aer_framework_results_data_mps_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ -//using cmat = std::vector>; -struct DataMPS : public DataMap, - public DataMap, - public DataMap, - public DataMap { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataMPS &combine(DataMPS &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataMPS &DataMPS::combine(DataMPS &&other) { - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - return *this; -} - -void DataMPS::add_to_json(json_t &result) { - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rdict.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rdict.hpp deleted file mode 100644 index 8f9e0f55a..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rdict.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_rdict_hpp_ -#define _aer_framework_results_data_rdict_hpp_ - -#include -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataRDict : public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2> { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataRDict &combine(DataRDict &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataRDict &DataRDict::combine(DataRDict &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - return *this; -} - -void DataRDict::add_to_json(json_t &result) { - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvalue.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvalue.hpp deleted file mode 100644 index 901c84eb3..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvalue.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_rvalue_hpp_ -#define _aer_framework_results_data_rvalue_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataRValue : - public DataMap, - public DataMap, - public DataMap, - public DataMap, - public DataMap, - public DataMap { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataRValue &combine(DataRValue &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataRValue &DataRValue::combine(DataRValue &&other) { - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - DataMap::combine(std::move(other)); - return *this; -} - -void DataRValue::add_to_json(json_t &result) { - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); - DataMap::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvector.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvector.hpp deleted file mode 100644 index ab283f7ac..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/data_rvector.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_rvector_hpp_ -#define _aer_framework_results_data_rvector_hpp_ - -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" -#include "framework/results/data/subtypes/single_data.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" -#include "framework/types.hpp" - -namespace AER { - -//============================================================================ -// Result container for Qiskit-Aer -//============================================================================ - -struct DataRVector : public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2> { - - // Serialize engine data to JSON - void add_to_json(json_t &result); - - // Combine stored data - DataRVector &combine(DataRVector &&other); -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -DataRVector &DataRVector::combine(DataRVector &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - return *this; -} - -void DataRVector::add_to_json(json_t &result) { - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); - DataMap, 1>::add_to_json(result); - DataMap, 2>::add_to_json(result); -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cdict.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cdict.hpp deleted file mode 100755 index 7bcddf3cd..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cdict.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_cdict_hpp_ -#define _aer_framework_result_data_pybind_data_cdict_hpp_ - -#include "framework/results/data/mixins/data_cdict.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataCDict container object to a new Python dict -py::object to_python(AER::DataCDict &&data); - -// Move an DataCDict container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataCDict &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataCDict &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataCDict &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cmatrix.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cmatrix.hpp deleted file mode 100755 index 4b53de3c8..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cmatrix.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_cmatrix_hpp_ -#define _aer_framework_result_data_pybind_data_cmatrix_hpp_ - -#include "framework/results/data/mixins/data_cmatrix.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataCMatrix container object to a new Python dict -py::object to_python(AER::DataCMatrix &&data); - -// Move an DataCMatrix container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataCMatrix &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataCMatrix &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataCMatrix &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_creg.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_creg.hpp deleted file mode 100755 index 9585154c4..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_creg.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_creg_hpp_ -#define _aer_framework_result_data_pybind_data_creg_hpp_ - -#include "framework/results/data/mixins/data_creg.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataCreg container object to a new Python dict -py::object to_python(AER::DataCreg &&data); - -// Move an DataCreg container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataCreg &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataCreg &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataCreg &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cvector.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cvector.hpp deleted file mode 100755 index 3115cc8b0..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_cvector.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_cvector_hpp_ -#define _aer_framework_result_data_pybind_data_cvector_hpp_ - -#include "framework/results/data/mixins/data_cvector.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataCVector container object to a new Python dict -py::object to_python(AER::DataCVector &&data); - -// Move an DataCVector container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataCVector &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataCVector &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataCVector &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_json.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_json.hpp deleted file mode 100755 index 89759ed3c..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_json.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_json_hpp_ -#define _aer_framework_result_data_pybind_data_json_hpp_ - -#include "framework/results/data/mixins/data_json.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataJSON container object to a new Python dict -py::object to_python(AER::DataJSON &&data); - -// Move an DataJSON container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataJSON &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataJSON &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataJSON &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_mps.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_mps.hpp deleted file mode 100755 index 7196d884a..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_mps.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_mps_hpp_ -#define _aer_framework_result_data_pybind_data_mps_hpp_ - -#include "framework/results/data/mixins/data_mps.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move mps_container_t to python object -template <> py::object to_python(AER::mps_container_t &&mps); - -// Move an DataMPS container object to a new Python dict -py::object to_python(AER::DataMPS &&data); - -// Move an DataMPS container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataMPS &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -template <> py::object AerToPy::to_python(AER::mps_container_t &&data) { - py::list mats; - for (auto& pair: data.first) { - mats.append(py::make_tuple(AerToPy::to_python(std::move(pair.first)), - AerToPy::to_python(std::move(pair.second)))); - } - py::list vecs; - for (auto&& vec: data.second) { - vecs.append(AerToPy::to_python(std::move(vec))); - } - return py::make_tuple(std::move(mats), std::move(vecs)); -} - -py::object AerToPy::to_python(AER::DataMPS &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataMPS &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rdict.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rdict.hpp deleted file mode 100755 index 03e2a0a30..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rdict.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_rdict_hpp_ -#define _aer_framework_result_data_pybind_data_rdict_hpp_ - -#include "framework/results/data/mixins/data_rdict.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataRDict container object to a new Python dict -py::object to_python(AER::DataRDict &&data); - -// Move an DataRDict container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataRDict &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataRDict &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataRDict &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvalue.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvalue.hpp deleted file mode 100755 index 15d9f1846..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvalue.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_rvalue_hpp_ -#define _aer_framework_result_data_pybind_data_rvalue_hpp_ - -#include "framework/results/data/mixins/data_rvalue.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataRValue container object to a new Python dict -py::object to_python(AER::DataRValue &&data); - -// Move an DataRValue container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataRValue &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataRValue &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataRValue &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvector.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvector.hpp deleted file mode 100755 index 58ca61ec9..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/mixins/pybind_data_rvector.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_rvector_hpp_ -#define _aer_framework_result_data_pybind_data_rvector_hpp_ - -#include "framework/results/data/mixins/data_rvector.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -//------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion -//------------------------------------------------------------------------------ - -namespace AerToPy { - -// Move an DataRVector container object to a new Python dict -py::object to_python(AER::DataRVector &&data); - -// Move an DataRVector container object to an existing new Python dict -void add_to_python(py::dict &pydata, AER::DataRVector &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -py::object AerToPy::to_python(AER::DataRVector &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, std::move(data)); - return std::move(pydata); -} - -void AerToPy::add_to_python(py::dict &pydata, AER::DataRVector &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/pybind_data.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/pybind_data.hpp deleted file mode 100755 index dcd25fb17..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/pybind_data.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_data_hpp_ -#define _aer_framework_result_data_pybind_data_hpp_ - -#include "framework/results/data/data.hpp" -#include "framework/results/data/mixins/pybind_data_creg.hpp" -#include "framework/results/data/mixins/pybind_data_rdict.hpp" -#include "framework/results/data/mixins/pybind_data_rvalue.hpp" -#include "framework/results/data/mixins/pybind_data_rvector.hpp" -#include "framework/results/data/mixins/pybind_data_cmatrix.hpp" -#include "framework/results/data/mixins/pybind_data_cvector.hpp" -#include "framework/results/data/mixins/pybind_data_cdict.hpp" -#include "framework/results/data/mixins/pybind_data_json.hpp" -#include "framework/results/data/mixins/pybind_data_mps.hpp" - -namespace AerToPy { - -// Move an ExperimentResult data object to a Python dict -template <> py::object to_python(AER::Data &&data); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -template <> -py::object AerToPy::to_python(AER::Data &&data) { - py::dict pydata; - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - return std::move(pydata); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/pybind_metadata.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/pybind_metadata.hpp deleted file mode 100755 index 244083d93..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/pybind_metadata.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2020. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_result_data_pybind_metadata_hpp_ -#define _aer_framework_result_data_pybind_metadata_hpp_ - -#include "framework/results/data/metadata.hpp" -#include "framework/results/data/subtypes/pybind_data_map.hpp" - -namespace AerToPy { - -// Move an ExperimentResult metdata object to a Python dict -template <> py::object to_python(AER::Metadata &&metadata); - -} //end namespace AerToPy - - -//============================================================================ -// Implementations -//============================================================================ - -template <> -py::object AerToPy::to_python(AER::Metadata &&metadata) { - py::dict pydata; - add_to_python(pydata, static_cast&&>(metadata)); - add_to_python(pydata, static_cast&&>(metadata)); - add_to_python(pydata, static_cast&&>(metadata)); - return std::move(pydata); -} - -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/accum_data.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/accum_data.hpp deleted file mode 100755 index a424f8a10..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/accum_data.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_subtypes_accum_hpp_ -#define _aer_framework_results_data_subtypes_accum_hpp_ - -#include "framework/linalg/linalg.hpp" -#include "framework/results/data/subtypes/single_data.hpp" - -namespace AER { - -template -class AccumData : public SingleData { -using Base = SingleData; -public: - // Add data (copy) - void add(const T& data); - - // Add data (move) - void add(T&& data); - - // Combine data (move) - void combine(AccumData&& other); - - // Clear all stored data - void clear(); - -protected: - bool empty_ = true; -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -template -void AccumData::add(const T& data) { - if (empty_) { - Base::data_ = data; - empty_ = false; - } else { - Linalg::iadd(Base::data_, data); - } -} - -template -void AccumData::add(T&& data) { - if (empty_) { - Base::data_ = std::move(data); - empty_ = false; - } else { - Linalg::iadd(Base::data_, std::move(data)); - } -} - -template -void AccumData::combine(AccumData&& other) { - add(std::move(other.data_)); -} - -template -void AccumData::clear() { - Base::clear(); - empty_ = true; -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/average_data.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/average_data.hpp deleted file mode 100755 index fea9a7c85..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/average_data.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_subtypes_average_hpp_ -#define _aer_framework_results_data_subtypes_average_hpp_ - -#include "framework/results/data/subtypes/accum_data.hpp" - -namespace AER { - -template -class AverageData : public AccumData { -using Base = AccumData; -public: - // Access data - T& value(); - - // Add data (copy) - void add(const T& data); - - // Add data (move) - void add(T&& data); - - // Add data - void combine(AverageData&& other); - - // Clear all stored data - void clear(); - - // Divide accum by counts to convert to the normalized mean - void normalize(); - - // Multiply accum by counts to convert to the un-normalized mean - void denormalize(); - -protected: - // Number of datum that have been accumulated - size_t count_ = 0; - - // Flag for whether the accumulated data has been divided - // by the count - bool normalized_ = false; -}; - -//------------------------------------------------------------------------------ -// Implementation -//------------------------------------------------------------------------------ - -template -void AverageData::add(const T& data) { - denormalize(); - Base::add(data); - count_ += 1; -} - -template -void AverageData::add(T&& data) { - denormalize(); - Base::add(std::move(data)); - count_ += 1; -} - -template -void AverageData::combine(AverageData&& other) { - denormalize(); - other.denormalize(); - Base::combine(std::move(other)); - count_ += other.count_; -} - -template -void AverageData::clear() { - Base::clear(); - count_ = 0; - normalized_ = false; -} - -template -void AverageData::normalize() { - if (normalized_) - return; - Linalg::idiv(Base::data_, double(count_)); - normalized_ = true; -} - -template -void AverageData::denormalize() { - if (!normalized_) - return; - Linalg::imul(Base::data_, double(count_)); - normalized_ = false; -} - -template -T& AverageData::value() { - normalize(); - return Base::data_; -} - -//------------------------------------------------------------------------------ -} // end namespace AER -//------------------------------------------------------------------------------ -#endif diff --git a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/data_map.hpp b/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/data_map.hpp deleted file mode 100755 index 7f0d4fb0a..000000000 --- a/quantum/plugins/ibm/aer/src/framework/results/data/subtypes/data_map.hpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * This code is part of Qiskit. - * - * (C) Copyright IBM 2021. - * - * This code is licensed under the Apache License, Version 2.0. You may - * obtain a copy of this license in the LICENSE.txt file in the root directory - * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. - * - * Any modifications or derivative works of this code must retain this - * copyright notice, and modified files need to carry a notice indicating - * that they have been altered from the originals. - */ - -#ifndef _aer_framework_results_data_map_hpp_ -#define _aer_framework_results_data_map_hpp_ - -#include "framework/json.hpp" -#include "framework/types.hpp" - -namespace AER { - -// Recursive nested data template class -template