diff --git a/CMakeLists.txt b/CMakeLists.txt index 95f91281..4010dc0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,15 @@ endif() find_package(XACC REQUIRED) find_package(Clang 10.0.0 REQUIRED) +# Multi +if (XACC_MULTI_THREADED) + message(STATUS "XACC is built with _XACC_MUTEX") + set(_QCOR_MUTEX True) +else() + message(STATUS "XACC is built with _XACC_MUTEX (default)") + set(_QCOR_MUTEX False) +endif() + configure_file("${CMAKE_SOURCE_DIR}/cmake/qcor_config.hpp.in" "${CMAKE_BINARY_DIR}/qcor_config.hpp") install (FILES ${CMAKE_BINARY_DIR}/qcor_config.hpp DESTINATION include/qcor) diff --git a/cmake/qcor_config.hpp.in b/cmake/qcor_config.hpp.in index 8b4a8f39..fa2055df 100644 --- a/cmake/qcor_config.hpp.in +++ b/cmake/qcor_config.hpp.in @@ -3,3 +3,4 @@ #define QCOR_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}" #define XACC_ROOT "${XACC_ROOT}" #define LLVM_ROOT "${LLVM_INSTALL_PREFIX}" +#cmakedefine _QCOR_MUTEX \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0b961f9d..8e622465 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -76,7 +76,14 @@ add_qcor_compile_and_exe_test(qrt_qpu_lambda_compute_action qpu_lambda/lambda_wi add_qcor_compile_and_exe_test(qrt_qpu_arith_adder arithmetic/simple.cpp) add_qcor_compile_and_exe_test(qrt_qpu_arith_integer_add arithmetic/integer_add.cpp) +# Multi-threading tests +add_qcor_compile_and_exe_test(qrt_simple-objective-function-async simple/simple-objective-function-async.cpp) +add_qcor_compile_and_exe_test(qrt_simple-objective-function-threaded simple/simple-objective-function-threaded.cpp) +add_qcor_compile_and_exe_test(qrt_bell-threaded simple/bell_threaded.cpp) +add_qcor_compile_and_exe_test(qrt_qpu_lambda_bell_threaded qpu_lambda/lambda_test_bell_threaded.cpp) +add_qcor_compile_and_exe_test(qrt_qpu_lambda_deuteron_vqe_threaded qpu_lambda/deuteron_vqe_threaded.cpp) +add_qcor_compile_and_exe_test(qrt_qpu_lambda_deuteron_vqe_objfunc_threaded qpu_lambda/deuteron_vqe_obj_func_threaded.cpp) if (QCOR_BUILD_QSHARP_TESTS) add_subdirectory(qsharp) -endif() \ No newline at end of file +endif() diff --git a/examples/qpu_lambda/deuteron_threaded.cpp b/examples/qpu_lambda/deuteron_threaded.cpp new file mode 100644 index 00000000..ee4a1c80 --- /dev/null +++ b/examples/qpu_lambda/deuteron_threaded.cpp @@ -0,0 +1,48 @@ +#include "qcor.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +void foo() { + + auto ansatz_X0X1 = qpu_lambda([](qreg q, double x) { + X(q[0]); + Ry(q[1], x); + CX(q[1], q[0]); + H(q); + Measure(q); + }); + + OptFunction obj( + [&](const std::vector &x, std::vector &) { + auto q = qalloc(2); + ansatz_X0X1(q, x[0]); + auto exp = q.exp_val_z(); + print("{1.2}}, {"maxeval", 10}}); + auto [opt_val, opt_params] = optimizer->optimize(obj); + print("opt_val = ", opt_val); +} + +int main(int argc, char **argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} diff --git a/examples/qpu_lambda/deuteron_vqe_obj_func_threaded.cpp b/examples/qpu_lambda/deuteron_vqe_obj_func_threaded.cpp new file mode 100644 index 00000000..d718621f --- /dev/null +++ b/examples/qpu_lambda/deuteron_vqe_obj_func_threaded.cpp @@ -0,0 +1,61 @@ +#include "qcor.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +void foo() { + // Create the Hamiltonian + auto H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - + 6.125 * Z(1) + 5.907; + int iter_count = 0; + auto ansatz = qpu_lambda( + [](qreg q, double x) { + X(q[0]); + Ry(q[1], x); + CX(q[1], q[0]); + print("Iter", iter_count, "; angle = ", x); + iter_count++; + }, + iter_count); + + auto q = qalloc(2); + auto objective = createObjectiveFunction(ansatz, H, q, 1); + // Create a qcor Optimizer + auto optimizer = createOptimizer("nlopt"); + + // Optimize the above function + auto [optval, opt_params] = optimizer->optimize(*objective.get()); + std::cout << "Energy: " << optval << "\n"; + qcor_expect(std::abs(optval + 1.74886) < 0.1); + + auto ansatz_vec_param = qpu_lambda([](qreg q, std::vector x) { + X(q[0]); + Ry(q[1], x[0]); + CX(q[1], q[0]); + }); + + auto q1 = qalloc(2); + auto objective_vec = createObjectiveFunction(ansatz_vec_param, H, q1, 1); + + // Optimize the above function + auto [optval_vec, opt_params_vec] = optimizer->optimize(*objective_vec.get()); + std::cout << "Energy: " << optval_vec << "\n"; + qcor_expect(std::abs(optval_vec + 1.74886) < 0.1); +} + +int main(int argc, char **argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} diff --git a/examples/qpu_lambda/deuteron_vqe_threaded.cpp b/examples/qpu_lambda/deuteron_vqe_threaded.cpp new file mode 100644 index 00000000..3de4bace --- /dev/null +++ b/examples/qpu_lambda/deuteron_vqe_threaded.cpp @@ -0,0 +1,60 @@ +#include "qcor.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +void foo() { + // Create the Hamiltonian + auto H = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - + 6.125 * Z(1) + 5.907; + + auto ansatz = qpu_lambda([](qreg q, double x) { + print("x = ", x); + X(q[0]); + Ry(q[1], x); + CX(q[1], q[0]); + }); + + auto ansatz_take_vec = qpu_lambda([](qreg q, std::vector x) { + print("x = ", x[0]); + X(q[0]); + Ry(q[1], x[0]); + CX(q[1], q[0]); + }); + + ObjectiveFunction opt_function_vec( + [&](std::vector x) { + return ansatz_take_vec.observe(H, qalloc(2), x); + }, + 1); + + // Show off optimize from ObjectiveFunction rvalue + auto optimizer = createOptimizer("nlopt"); + auto [ground_energy, opt_params] = optimizer->optimize(ObjectiveFunction( + [&](std::vector x) { return ansatz.observe(H, qalloc(2), x[0]); }, + 1)); + print("Energy: ", ground_energy); + qcor_expect(std::abs(ground_energy + 1.74886) < 0.1); + + auto [ground_energy_vec, opt_params_vec] = + optimizer->optimize(opt_function_vec); + print("Energy: ", ground_energy_vec); + qcor_expect(std::abs(ground_energy_vec + 1.74886) < 0.1); +} + +int main(int argc, char **argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} \ No newline at end of file diff --git a/examples/qpu_lambda/lambda_test_bell_threaded.cpp b/examples/qpu_lambda/lambda_test_bell_threaded.cpp new file mode 100644 index 00000000..61013fe2 --- /dev/null +++ b/examples/qpu_lambda/lambda_test_bell_threaded.cpp @@ -0,0 +1,43 @@ +#include "qcor.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +void foo() { + auto x_lambda = qpu_lambda([](qubit q) { + X(q); }); + + auto bell = qpu_lambda([](qreg q) { + H(q[0]); + // Call the captured lambda + x_lambda.ctrl(q[0], q[1]); + Measure(q); + }, x_lambda); + + auto q = qalloc(2); + bell(q); + q.print(); + qcor_expect(q.counts().size() == 2); + qcor_expect(q.counts()["00"] > 400); + qcor_expect(q.counts()["11"] > 400); + // Entangled... + qcor_expect(q.counts()["00"] + q.counts()["11"] == 1024); +} + +int main(int argc, char **argv) { + set_shots(1024); +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} diff --git a/examples/simple/bell_threaded.cpp b/examples/simple/bell_threaded.cpp new file mode 100644 index 00000000..751ea81e --- /dev/null +++ b/examples/simple/bell_threaded.cpp @@ -0,0 +1,42 @@ +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +// Define the bell kernel +__qpu__ void bell(qreg q) { + using qcor::xasm; + H(q[0]); + CX(q[0], q[1]); + + for (int i = 0; i < q.size(); i++) { + Measure(q[i]); + } +} + +void foo() { + // Create two qubit registers, each size 2 + auto q = qalloc(2); + + // Run the quantum kernel + bell(q); + + // dump the results + q.print(); +} + +int main(int argc, char **argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} diff --git a/examples/simple/simple-objective-function-async.cpp b/examples/simple/simple-objective-function-async.cpp new file mode 100644 index 00000000..b5762ecf --- /dev/null +++ b/examples/simple/simple-objective-function-async.cpp @@ -0,0 +1,72 @@ +// Note no includes here, we are just +// using the language extension +// +// run this with +// qcor -qpu qpp simple-objective-function-async.cpp +// ./a.out + +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#include +#endif + +__qpu__ void ansatz(qreg q, double theta) { + X(q[0]); + Ry(q[1], theta); + CX(q[1], q[0]); +} + +int main(int argc, char **argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: execute taskInitiate asynchronously" << std::endl; +#else + std::cout << "_QCOR_MUTEX is NOT defined: execute taskInitiate sequentially" << std::endl; +#endif + // Allocate 2 qubits + auto q1 = qalloc(2); + auto q2 = qalloc(2); + + // Programmer needs to set + // the number of variational params + auto n_variational_params1 = 1; + auto n_variational_params2 = 1; + + // Create the Deuteron Hamiltonian + auto H1 = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - + 6.125 * Z(1); + auto H2 = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - + 6.125 * Z(1); + + // Create the ObjectiveFunction, here we want to run VQE + // need to provide ansatz, Operator, and qreg + auto objective1 = createObjectiveFunction(ansatz, H1, q1, n_variational_params1, + {{"gradient-strategy", "central"}, {"step", 1e-3}}); + auto objective2 = createObjectiveFunction(ansatz, H2, q2, n_variational_params2, + {{"gradient-strategy", "central"}, {"step", 1e-3}}); + + // Create the Optimizer. + auto optimizer1 = createOptimizer("nlopt", {{"nlopt-optimizer", "l-bfgs"}}); + auto optimizer2 = createOptimizer("nlopt", {{"nlopt-optimizer", "l-bfgs"}}); + +#ifdef _QCOR_MUTEX + // Launch the two optimizations asynchronously + auto handle1 = std::async(std::launch::async, [=]() -> std::pair> { return optimizer1->optimize(objective1); }); + auto handle2 = std::async(std::launch::async, [=]() -> std::pair> { return optimizer2->optimize(objective2); }); + + // Go do other work... + + // Query results when ready. + auto [opt_val1, opt_params1] = handle1.get(); + auto [opt_val2, opt_params2] = handle2.get(); +#else + // Launch the two optimizations sequentially + auto [opt_val1, opt_params1] = optimizer1->optimize(objective1); + auto [opt_val2, opt_params2] = optimizer2->optimize(objective2); +#endif + qcor_expect(std::abs(opt_val1 + 1.74886) < 0.1); + qcor_expect(std::abs(opt_val2 + 1.74886) < 0.1); + +} \ No newline at end of file diff --git a/examples/simple/simple-objective-function-threaded.cpp b/examples/simple/simple-objective-function-threaded.cpp new file mode 100644 index 00000000..630ec732 --- /dev/null +++ b/examples/simple/simple-objective-function-threaded.cpp @@ -0,0 +1,66 @@ +// Note no includes here, we are just +// using the language extension +// +// run this with +// qcor -qpu qpp simple-objective-function-threaded.cpp +// ./a.out + +// for _QCOR_MUTEX +#include "qcor_config.hpp" +#ifdef _QCOR_MUTEX +#include +#include +#endif + +__qpu__ void ansatz(qreg q, double theta) { + X(q[0]); + Ry(q[1], theta); + CX(q[1], q[0]); +} + +void foo() { + // Allocate 2 qubits + auto q = qalloc(2); + + // Programmer needs to set + // the number of variational params + auto n_variational_params = 1; + + // Create the Deuteron Hamiltonian + auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - + 6.125 * Z(1); + + // Create the ObjectiveFunction, here we want to run VQE + // need to provide ansatz, Operator, and qreg + auto objective = createObjectiveFunction(ansatz, H, q, n_variational_params, + {{"gradient-strategy", "central"}, {"step", 1e-3}}); + + // Create the Optimizer. + auto optimizer = createOptimizer("nlopt", {{"nlopt-optimizer", "l-bfgs"}}); + + // Launch the Optimization Task with taskInitiate + // auto handle = taskInitiate(objective, optimizer); + auto [opt_val, opt_params] = optimizer->optimize(objective); + + // Go do other work... + + // Query results when ready. + // auto results = sync(handle); + // printf("vqe-energy from taskInitiate = %f\n", results.opt_val); + qcor_expect(std::abs(opt_val + 1.74886) < 0.1); + +} + +int main(int argc, char** argv) { +#ifdef _QCOR_MUTEX + std::cout << "_QCOR_MUTEX is defined: multi-threding execution" << std::endl; + std::thread t0(foo); + std::thread t1(foo); + t0.join(); + t1.join(); +#else + std::cout << "_QCOR_MUTEX is NOT defined: sequential execution" << std::endl; + foo(); + foo(); +#endif +} diff --git a/handlers/CMakeLists.txt b/handlers/CMakeLists.txt index 4ea4b4eb..c6a8aef3 100644 --- a/handlers/CMakeLists.txt +++ b/handlers/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(${LIBRARY_NAME} target_include_directories(${LIBRARY_NAME} PUBLIC . + ${XACC_ROOT}/include/xacc ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) diff --git a/handlers/qcor_syntax_handler.cpp b/handlers/qcor_syntax_handler.cpp index a841822b..c360d8f9 100644 --- a/handlers/qcor_syntax_handler.cpp +++ b/handlers/qcor_syntax_handler.cpp @@ -12,6 +12,14 @@ using namespace clang; +// for _QCOR_MUTEX +#include "qcor_config.hpp" + +#ifdef _QCOR_MUTEX +#include +#pragma message ("_QCOR_MUTEX is ON") +#endif + namespace qcor { namespace __internal__developer__flags__ { bool add_predefines = true; @@ -177,12 +185,21 @@ void QCORSyntaxHandler::GetReplacement( // declare protected operator()() method OS << "protected:\n"; +#ifdef _QCOR_MUTEX + OS << "static std::recursive_mutex& getMutex() {\n"; + OS << "static std::recursive_mutex m;\n"; + OS << "return m;\n"; + OS << "}\n"; +#endif OS << "void operator()(" << program_arg_types[0] << " " << program_parameters[0]; for (int i = 1; i < program_arg_types.size(); i++) { OS << ", " << program_arg_types[i] << " " << program_parameters[i]; } OS << ") {\n"; +#ifdef _QCOR_MUTEX + OS << "std::lock_guard lock(getMutex());\n"; +#endif OS << "if (!parent_kernel) {\n"; OS << "parent_kernel = " "qcor::__internal__::create_composite(kernel_name);\n"; @@ -287,7 +304,9 @@ void QCORSyntaxHandler::GetReplacement( // Destructor definition OS << "virtual ~" << kernel_name << "() {\n"; OS << "if (disable_destructor) {return;}\n"; - +#ifdef _QCOR_MUTEX + OS << "std::lock_guard lock(getMutex());\n"; +#endif OS << "auto [" << program_parameters[0]; for (int i = 1; i < program_parameters.size(); i++) { OS << ", " << program_parameters[i]; @@ -526,6 +545,9 @@ void QCORSyntaxHandler::AddToPredefines(llvm::raw_string_ostream &OS) { OS << "#include \"qcor.hpp\"\n"; OS << "using namespace qcor;\n"; OS << "using namespace xacc::internal_compiler;\n"; +#ifdef _QCOR_MUTEX + OS << "#include \n"; +#endif } } diff --git a/runtime/jit/CMakeLists.txt b/runtime/jit/CMakeLists.txt index cc965502..61fe69b2 100644 --- a/runtime/jit/CMakeLists.txt +++ b/runtime/jit/CMakeLists.txt @@ -9,7 +9,7 @@ add_library(${LIBRARY_NAME} ${CMAKE_BINARY_DIR}/runtime/jit/qcor_jit.cpp) target_include_directories(${LIBRARY_NAME} - PUBLIC . ../qrt ../utils ../qrt/ir ${CMAKE_SOURCE_DIR}/runtime/qrt/internal_compiler ${XACC_ROOT}/include/xacc ${CMAKE_SOURCE_DIR}/handlers + PUBLIC . ../qrt ../utils ../qrt/ir ${CMAKE_SOURCE_DIR}/runtime/qrt/internal_compiler ${CMAKE_BINARY_DIR} ${XACC_ROOT}/include/xacc ${CMAKE_SOURCE_DIR}/handlers ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) diff --git a/runtime/jit/qcor_jit.in.cpp b/runtime/jit/qcor_jit.in.cpp index bd1fe8ac..d3a3aa3d 100644 --- a/runtime/jit/qcor_jit.in.cpp +++ b/runtime/jit/qcor_jit.in.cpp @@ -52,6 +52,13 @@ #include "qrt.hpp" #include "xacc.hpp" #include "xacc_internal_compiler.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" + +#ifdef _QCOR_MUTEX +#include +#pragma message ("_QCOR_MUTEX is ON") +#endif using namespace llvm; using namespace llvm::orc; @@ -63,6 +70,12 @@ using namespace llvm::orc; namespace qcor { +namespace __internal__ { +#ifdef _QCOR_MUTEX +std::mutex qcor_qjit_lock; +#endif +} + using namespace clang; class LexerHelper { @@ -400,6 +413,9 @@ class LLVMJIT { }; QJIT::QJIT() { +#ifdef _QCOR_MUTEX + std::lock_guard l(__internal__::qcor_qjit_lock); +#endif // if tmp directory doesnt exist create it qjit_cache_path = std::string(std::getenv("HOME")) + "/.qjit"; if (!xacc::directoryExists(qjit_cache_path)) { @@ -428,6 +444,10 @@ QJIT::QJIT() { } } void QJIT::write_cache() { +#ifdef _QCOR_MUTEX + std::lock_guard l(__internal__::qcor_qjit_lock); +#endif + std::string cache_file_loc = qjit_cache_path + "/qjit_cache.json"; // MAKE SURE WE DONT OVERWRITE @@ -458,6 +478,9 @@ QJIT::~QJIT() { write_cache(); } void QJIT::jit_compile(std::unique_ptr m, std::vector extra_shared_lib_paths) { +#ifdef _QCOR_MUTEX + std::lock_guard l(__internal__::qcor_qjit_lock); +#endif std::vector seen_functions; for (Function &f : *m) { auto name = f.getName().str(); @@ -486,6 +509,9 @@ void QJIT::jit_compile(const std::string &code, const std::vector &kernel_dependency, const std::string &extra_functions_src, std::vector extra_headers) { +#ifdef _QCOR_MUTEX + std::lock_guard l(__internal__::qcor_qjit_lock); +#endif // Run the Syntax Handler to get the kernel name and // the kernel code (the QuantumKernel subtype def + utility functions) auto [kernel_name, new_code] = @@ -693,7 +719,6 @@ void QJIT::jit_compile(const std::string &code, kernel_name_to_f_ptr_parent_hetmap.insert( {kernel_name, parent_hetmap_rawFPtr}); } - return; } diff --git a/runtime/objectives/objective_function.cpp b/runtime/objectives/objective_function.cpp index 49ffa434..fb0955ca 100644 --- a/runtime/objectives/objective_function.cpp +++ b/runtime/objectives/objective_function.cpp @@ -2,9 +2,25 @@ #include "xacc.hpp" #include "xacc_service.hpp" #include "xacc_internal_compiler.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" + +#ifdef _QCOR_MUTEX +#include +#pragma message ("_QCOR_MUTEX is ON") +#endif + namespace qcor { namespace __internal__ { + +#ifdef _QCOR_MUTEX +std::mutex qcor_xacc_init_lock; +#endif + std::shared_ptr get_objective(const std::string &type) { +#ifdef _QCOR_MUTEX + std::lock_guard lock(qcor_xacc_init_lock); +#endif if (!xacc::isInitialized()) xacc::internal_compiler::compiler_InitializeXACC(); return xacc::getService(type); diff --git a/runtime/objectives/vqe/vqe.cpp b/runtime/objectives/vqe/vqe.cpp index 72ec0022..184da61b 100644 --- a/runtime/objectives/vqe/vqe.cpp +++ b/runtime/objectives/vqe/vqe.cpp @@ -14,6 +14,8 @@ using namespace cppmicroservices; #include "xacc_plugin.hpp" #include "xacc_service.hpp" +#include "Cloneable.hpp" + namespace { template @@ -29,7 +31,7 @@ std::ostream &operator<<(std::ostream &os, const std::vector &v) { } // namespace namespace qcor { -class VQEObjective : public ObjectiveFunction { +class VQEObjective : public ObjectiveFunction, public xacc::Cloneable { public: std::shared_ptr vqe; double operator()(xacc::internal_compiler::qreg &qreg, @@ -146,6 +148,9 @@ class VQEObjective : public ObjectiveFunction { int current_iteration = 0; const std::string name() const override { return "vqe"; } const std::string description() const override { return ""; } + std::shared_ptr clone() override { + return std::make_shared(); + } }; } // namespace qcor diff --git a/runtime/optimizer/qcor_optimizer.cpp b/runtime/optimizer/qcor_optimizer.cpp index 4eb872c9..9c246c6f 100644 --- a/runtime/optimizer/qcor_optimizer.cpp +++ b/runtime/optimizer/qcor_optimizer.cpp @@ -6,9 +6,22 @@ #include "xacc.hpp" #include "xacc_internal_compiler.hpp" #include "xacc_service.hpp" +// for _QCOR_MUTEX +#include "qcor_config.hpp" + +#ifdef _QCOR_MUTEX +#include +#pragma message ("_QCOR_MUTEX is ON") +#endif namespace qcor { +namespace __internal__ { +#ifdef _QCOR_MUTEX +extern std::mutex qcor_xacc_init_lock; +#endif +} + /// ------------- Optimizer Wrapper --------------- Optimizer::Optimizer() = default; Optimizer::Optimizer(const std::string &name) @@ -74,6 +87,9 @@ Optimizer::OptimizerImpl *Optimizer::operator->() { std::shared_ptr createOptimizer(const std::string &type, xacc::HeterogeneousMap &&options) { +#ifdef _QCOR_MUTEX + std::lock_guard lock(__internal__::qcor_xacc_init_lock); +#endif if (!xacc::isInitialized()) xacc::internal_compiler::compiler_InitializeXACC(); auto xacc_opt = xacc::getOptimizer(type, options);