diff --git a/.gitmodules b/.gitmodules index 3d7295622..ef75a52d5 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/ORNL-QCI/nlopt + url = https://github.com/stevengj/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/CMakeLists.txt b/CMakeLists.txt index 823814264..614136b66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,12 +21,19 @@ 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() 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) @@ -216,37 +223,42 @@ endif() add_subdirectory(xacc) add_subdirectory(quantum) -find_package(Python COMPONENTS Interpreter Development) +# qiree doesn't need python, so we can ignore this and everything else that is python related +if(NOT QIREE_MINIMAL_BUILD) -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) +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 @@ -265,13 +277,22 @@ 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/) -install(FILES "${NLOHMANN_INCLUDE_DIR}/nlohmann/json.hpp" DESTINATION include/xacc/) +if(NOT XACC_DEPS_EXTERNAL OR NOT nlohmann_json_FOUND) + install(FILES "${NLOHMANN_INCLUDE_DIR}/nlohmann/json.hpp" DESTINATION include/xacc/) +endif() -install(DIRECTORY "${SPDLOG_INCLUDE_DIR}" DESTINATION include/spdlog/) +if(NOT XACC_DEPS_EXTERNAL OR NOT spdlog_FOUND) + install(DIRECTORY "${SPDLOG_INCLUDE_DIR}" DESTINATION include/spdlog/) +endif() install(DIRECTORY "${CMAKE_SOURCE_DIR}/tpls/exprtk" DESTINATION include) -install(DIRECTORY "${EIGEN_INCLUDE_DIR}" DESTINATION include) +if(NOT XACC_DEPS_EXTERNAL OR NOT Eigen3_FOUND) + install(DIRECTORY "${EIGEN_INCLUDE_DIR}" DESTINATION include) +endif() 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/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/CMakeLists.txt b/quantum/observable/pauli/CMakeLists.txt index b0f68c313..d804b85fb 100644 --- a/quantum/observable/pauli/CMakeLists.txt +++ b/quantum/observable/pauli/CMakeLists.txt @@ -23,22 +23,15 @@ 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 - "${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) + 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}) add_dependencies(${LIBRARY_NAME} antlr4_shared) diff --git a/quantum/observable/pauli/PauliOperator.cpp b/quantum/observable/pauli/PauliOperator.cpp index 771a591cb..b921c7961 100644 --- a/quantum/observable/pauli/PauliOperator.cpp +++ b/quantum/observable/pauli/PauliOperator.cpp @@ -13,22 +13,11 @@ #include "PauliOperator.hpp" #include "CompositeInstruction.hpp" #include "IRProvider.hpp" -#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 { @@ -1107,7 +1096,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/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..baec94747 100644 --- a/quantum/plugins/CMakeLists.txt +++ b/quantum/plugins/CMakeLists.txt @@ -11,39 +11,38 @@ # 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) 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) 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..3292eec20 100644 --- a/quantum/plugins/algorithms/CMakeLists.txt +++ b/quantum/plugins/algorithms/CMakeLists.txt @@ -10,18 +10,22 @@ # Contributors: # Alexander J. McCaskey - initial API and implementation # *******************************************************************************/ -add_subdirectory(adapt) -add_subdirectory(vqe) -add_subdirectory(rdm) -add_subdirectory(ml) -add_subdirectory(rotoselect) -add_subdirectory(qpt) -add_subdirectory(qaoa) -add_subdirectory(qpe) -add_subdirectory(gradient_strategies) -add_subdirectory(qite) -add_subdirectory(qcmx) -add_subdirectory(qeom) + +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(NOT 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/algorithms/ml/ddcl/CMakeLists.txt b/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt index 7290ae289..55ad9cfa9 100644 --- a/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt +++ b/quantum/plugins/algorithms/ml/ddcl/CMakeLists.txt @@ -21,7 +21,8 @@ add_library(${LIBRARY_NAME} SHARED ${SRC}) target_include_directories( ${LIBRARY_NAME} - PUBLIC SYSTEM "${EIGEN_INCLUDE_DIR}") + PUBLIC . + ${EIGEN_INCLUDE_DIR}) target_link_libraries(${LIBRARY_NAME} PUBLIC xacc) 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/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") 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/optimizers/CMakeLists.txt b/quantum/plugins/optimizers/CMakeLists.txt index d764e5c20..bcfcf75ec 100644 --- a/quantum/plugins/optimizers/CMakeLists.txt +++ b/quantum/plugins/optimizers/CMakeLists.txt @@ -1,2 +1,23 @@ add_subdirectory(nlopt-optimizers) -add_subdirectory(mlpack) \ No newline at end of file +add_subdirectory(mlpack) +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 new file mode 100644 index 000000000..119ecf551 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/CMakeLists.txt @@ -0,0 +1,55 @@ +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}) + +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..38e4760fe --- /dev/null +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.cpp @@ -0,0 +1,165 @@ +#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); + } + + // 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..25235c3b6 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/scipy_optimizer.hpp @@ -0,0 +1,25 @@ +#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..8b3424303 --- /dev/null +++ b/quantum/plugins/optimizers/scipy/tests/ScipyOptimizerTester.cpp @@ -0,0 +1,98 @@ +#include +#include "xacc.hpp" +#include "xacc_service.hpp" +#include +#include + +using namespace xacc; +namespace py = pybind11; + +TEST(ScipyOptimizerTester, checkSimple) { + + auto optimizer = + xacc::getService("scipy"); + + 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; +} 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/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 diff --git a/tpls/cppmicroservices b/tpls/cppmicroservices index 98ac35a6f..8570c9e65 160000 --- a/tpls/cppmicroservices +++ b/tpls/cppmicroservices @@ -1 +1 @@ -Subproject commit 98ac35a6f6ffc70bd7701dcfc6b78e35537930fa +Subproject commit 8570c9e65296c146c2446f385f9aa741e18af0d6 diff --git a/tpls/nlopt b/tpls/nlopt index dc4ad82b6..c2ffc4002 160000 --- a/tpls/nlopt +++ b/tpls/nlopt @@ -1 +1 @@ -Subproject commit dc4ad82b6e374619efa423b585f7f96b875b2cb7 +Subproject commit c2ffc40024d160a829f63ac6b5ab23c4abfe78ef diff --git a/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp b/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp deleted file mode 100644 index 7b9a42913..000000000 --- a/xacc/optimizer/nlopt-optimizers/nlopt/src/api/nlopt-in.hpp +++ /dev/null @@ -1,559 +0,0 @@ -/* 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 */ 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);