Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions cmake/qcor_config.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 8 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
endif()
48 changes: 48 additions & 0 deletions examples/qpu_lambda/deuteron_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "qcor.hpp"
// for _QCOR_MUTEX
#include "qcor_config.hpp"
#ifdef _QCOR_MUTEX
#include <mutex>
#include <thread>
#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<double> &x, std::vector<double> &) {
auto q = qalloc(2);
ansatz_X0X1(q, x[0]);
auto exp = q.exp_val_z();
print("<X0X1(",x[0],") = ", exp);
return exp;
},
1);

auto optimizer = createOptimizer(
"nlopt",
{{"initial-parameters", std::vector<double>{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
}
61 changes: 61 additions & 0 deletions examples/qpu_lambda/deuteron_vqe_obj_func_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "qcor.hpp"
// for _QCOR_MUTEX
#include "qcor_config.hpp"
#ifdef _QCOR_MUTEX
#include <mutex>
#include <thread>
#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<double> 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
}
60 changes: 60 additions & 0 deletions examples/qpu_lambda/deuteron_vqe_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "qcor.hpp"
// for _QCOR_MUTEX
#include "qcor_config.hpp"
#ifdef _QCOR_MUTEX
#include <mutex>
#include <thread>
#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<double> x) {
print("x = ", x[0]);
X(q[0]);
Ry(q[1], x[0]);
CX(q[1], q[0]);
});

ObjectiveFunction opt_function_vec(
[&](std::vector<double> 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<double> 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
}
43 changes: 43 additions & 0 deletions examples/qpu_lambda/lambda_test_bell_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "qcor.hpp"
// for _QCOR_MUTEX
#include "qcor_config.hpp"
#ifdef _QCOR_MUTEX
#include <mutex>
#include <thread>
#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
}
42 changes: 42 additions & 0 deletions examples/simple/bell_threaded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// for _QCOR_MUTEX
#include "qcor_config.hpp"
#ifdef _QCOR_MUTEX
#include <mutex>
#include <thread>
#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
}
72 changes: 72 additions & 0 deletions examples/simple/simple-objective-function-async.cpp
Original file line number Diff line number Diff line change
@@ -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 <mutex>
#include <future>
#include <thread>
#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<double, std::vector<double>> { return optimizer1->optimize(objective1); });
auto handle2 = std::async(std::launch::async, [=]() -> std::pair<double, std::vector<double>> { 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);

}
Loading