Skip to content

Commit

Permalink
Allow state synthesis for remote simulators (#2212)
Browse files Browse the repository at this point in the history
* Copy pointer arguments for lazy evaluation on remote simulators
  • Loading branch information
annagrin committed Sep 19, 2024
1 parent 2c05ff1 commit 67b74c1
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 27 deletions.
5 changes: 3 additions & 2 deletions docs/sphinx/examples/cpp/other/trotter_kernel_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ int SPINS = 11; // set to around 25 qubits for `nvidia` target
int STEPS = 10; // set to around 100 for `nvidia` target

// Compile and run with:
// clang-format off
// ```
// nvq++ --enable-mlir -v trotter_kernel_mode.cpp -o trotter.x -target nvidia &&
// ./trotter.x
// nvq++ --enable-mlir -v trotter_kernel_mode.cpp -o trotter.x --target nvidia && ./trotter.x
// ```
// clang-format off

// Alternating up/down spins
struct initState {
Expand Down
22 changes: 16 additions & 6 deletions runtime/cudaq/qis/remote_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,28 @@ class RemoteSimulationState : public cudaq::SimulationState {
public:
template <typename T>
void addArgument(const T &arg) {
if constexpr (std::is_pointer<std::decay_t<T>>::value) {
args.push_back(const_cast<void *>(static_cast<const void *>(arg)));
deleters.push_back([](void *ptr) {});
} else if constexpr (std::is_copy_constructible<std::decay_t<T>>::value) {
if constexpr (std::is_pointer_v<std::decay_t<T>>) {
if constexpr (std::is_copy_constructible_v<
std::remove_pointer_t<std::decay_t<T>>>) {
auto ptr = new std::remove_pointer_t<std::decay_t<T>>(*arg);
args.push_back(ptr);
deleters.push_back([](void *ptr) {
delete static_cast<std::remove_pointer_t<std::decay_t<T>> *>(ptr);
});
} else {
throw std::invalid_argument(
"Unsupported argument type: only pointers to copy-constructible "
"types and copy-constructible types are supported.");
}
} else if constexpr (std::is_copy_constructible_v<std::decay_t<T>>) {
auto *ptr = new std::decay_t<T>(arg);
args.push_back(ptr);
deleters.push_back(
[](void *ptr) { delete static_cast<std::decay_t<T> *>(ptr); });
} else {
throw std::invalid_argument(
"Unsupported argument type: only pointers and "
"copy-constructible types are supported.");
"Unsupported argument type: only pointers to copy-constructible "
"types and copy-constructible types are supported.");
}
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/validate_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ do
# Skipped long-running tests (variational optimization loops) for the "remote-mqpu" target to keep CI runtime managable.
# A simplified test for these use cases is included in the 'test/Remote-Sim/' test suite.
# Skipped tests that require passing kernel callables to entry-point kernels for the "remote-mqpu" target.
if [[ "$ex" == *"vqe_h2"* || "$ex" == *"qaoa_maxcut"* || "$ex" == *"gradients"* || "$ex" == *"grover"* || "$ex" == *"multi_controlled_operations"* || "$ex" == *"phase_estimation"* || "$ex" == *"trotter_kernel"* || "$ex" == *"builder.cpp"* ]];
if [[ "$ex" == *"vqe_h2"* || "$ex" == *"qaoa_maxcut"* || "$ex" == *"gradients"* || "$ex" == *"grover"* || "$ex" == *"multi_controlled_operations"* || "$ex" == *"phase_estimation"* || "$ex" == *"trotter_kernel_mode"* || "$ex" == *"builder.cpp"* ]];
then
let "skipped+=1"
echo "Skipping $t target.";
Expand Down
22 changes: 11 additions & 11 deletions targettests/Remote-Sim/qvector_init_from_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ __qpu__ void test_state_param(cudaq::state* state) {

__qpu__ void test_state_param2(cudaq::state* state, cudaq::pauli_word w) {
cudaq::qvector q(state);
cudaq::exp_pauli(.5, q, w);
cudaq::exp_pauli(1.0, q, w);
}

__qpu__ void test_state_param3(cudaq::state *initial_state, std::vector<cudaq::pauli_word>& words) {
cudaq::qvector q(initial_state);
for (std::size_t i = 0; i < words.size(); ++i) {
cudaq::exp_pauli(.5, q, words[i]);
cudaq::exp_pauli(1.0, q, words[i]);
}
}

Expand All @@ -60,7 +60,7 @@ void printCounts(cudaq::sample_result& result) {

std::sort(values.begin(), values.end());
for (auto &&bits : values) {
std::cout << bits << '\n';
std::cout << bits << std::endl;
}
}

Expand All @@ -70,7 +70,7 @@ int main() {
auto state = cudaq::state::from_data(vec);
auto state1 = cudaq::state::from_data(vec1);
{
std::cout << "Passing state created from data as argument (kernel mode)\n";
std::cout << "Passing state created from data as argument (kernel mode)" << std::endl;
auto counts = cudaq::sample(test_state_param, &state);
printCounts(counts);

Expand All @@ -86,7 +86,7 @@ int main() {
// CHECK: 111

{
std::cout << "Passing state from another kernel as argument (kernel mode)\n";
std::cout << "Passing state from another kernel as argument (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state);
auto counts = cudaq::sample(test_state_param, &state);
printCounts(counts);
Expand All @@ -97,7 +97,7 @@ int main() {
// CHECK: 10

{
std::cout << "Passing large state from another kernel as argument (kernel mode)\n";
std::cout << "Passing large state from another kernel as argument (kernel mode)" << std::endl;
auto largeState = cudaq::get_state(test_init_large_state);
auto counts = cudaq::sample(test_state_param, &largeState);
printCounts(counts);
Expand All @@ -108,7 +108,7 @@ int main() {
// CHECK: 10000000000000

{
std::cout << "Passing state from another kernel as argument iteratively (kernel mode)\n";
std::cout << "Passing state from another kernel as argument iteratively (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state);
for (auto i = 0; i < 4; i++) {
auto counts = cudaq::sample(test_state_param2, &state, cudaq::pauli_word{"XX"});
Expand Down Expand Up @@ -141,7 +141,7 @@ int main() {
// CHECK: 11

{
std::cout << "Passing state from another kernel as argument iteratively with vector args (kernel mode)\n";
std::cout << "Passing state from another kernel as argument iteratively with vector args (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state);
auto words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XX"}};
for (auto i = 0; i < 4; i++) {
Expand Down Expand Up @@ -176,17 +176,17 @@ int main() {
// CHECK: 11

{
std::cout << "Passing state from another kernel as argument iteratively with vector args with 2 elements (kernel mode)\n";
std::cout << "Passing state from another kernel as argument iteratively with vector args with 2 elements (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state);
auto words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XX"}, cudaq::pauli_word{"YY"}};
auto coeffs = std::vector<double>{0.5, 0.6};
auto coeffs = std::vector<double>{1.0, 2.0};
for (auto i = 0; i < 4; i++) {
auto counts = cudaq::sample(test_state_param4, &state, coeffs, words);
std::cout << "Iteration: " << i << std::endl;
printCounts(counts);
state = cudaq::get_state(test_state_param4, &state, coeffs, words);
words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XY"}, cudaq::pauli_word{"YX"}};
coeffs = std::vector<double>{0.5 * i};
coeffs = std::vector<double>{1.0, 2.0};
}
}

Expand Down
141 changes: 134 additions & 7 deletions targettests/Remote-Sim/qvector_init_from_state_lazy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ struct test_state_param {
}
};

struct test_state_param2 {
void operator()(cudaq::state *initial_state, cudaq::pauli_word w) __qpu__ {
cudaq::qvector q(initial_state);
cudaq::exp_pauli(1.0, q, w);
}
};

struct test_state_param3 {
void operator()(cudaq::state *initial_state, std::vector<cudaq::pauli_word>& words) __qpu__ {
cudaq::qvector q(initial_state);
for (std::size_t i = 0; i < words.size(); ++i) {
cudaq::exp_pauli(1.0, q, words[i]);
}
}
};

struct test_state_param4 {
void operator()(cudaq::state *initial_state, std::vector<double> &coefficients, std::vector<cudaq::pauli_word>& words) __qpu__ {
cudaq::qvector q(initial_state);
for (std::size_t i = 0; i < words.size(); ++i) {
cudaq::exp_pauli(coefficients[i], q, words[i]);
}
}
};

void printCounts(cudaq::sample_result& result) {
std::vector<std::string> values{};
for (auto &&[bits, counts] : result) {
Expand All @@ -45,7 +70,7 @@ void printCounts(cudaq::sample_result& result) {

std::sort(values.begin(), values.end());
for (auto &&bits : values) {
std::cout << bits << '\n';
std::cout << bits << std::endl;;
}
}

Expand All @@ -55,37 +80,139 @@ int main() {
auto state = cudaq::state::from_data(vec);
auto state1 = cudaq::state::from_data(vec1);
{
// Passing state created from data as argument (kernel mode)
std::cout << "Passing state created from data as argument (kernel mode)" << std::endl;
auto counts = cudaq::sample(test_state_param{}, &state);
printCounts(counts);

counts = cudaq::sample(test_state_param{}, &state1);
printCounts(counts);
}

// CHECK: Passing state created from data as argument (kernel mode)
// CHECK: 000
// CHECK: 100

// CHECK: 011
// CHECK: 111

{
// Passing state from another kernel as argument (kernel mode)
std::cout << "Passing state from another kernel as argument (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state{});
auto counts = cudaq::sample(test_state_param{}, &state);
printCounts(counts);
}

// CHECK: Passing state from another kernel as argument (kernel mode)
// CHECK: 00
// CHECK: 10

{
// Passing large state from another kernel as argument (kernel mode)
std::cout << "Passing large state from another kernel as argument (kernel mode)" << std::endl;
auto largeState = cudaq::get_state(test_init_large_state{});
auto counts = cudaq::sample(test_state_param{}, &largeState);
printCounts(counts);
}

// CHECK: Passing large state from another kernel as argument (kernel mode)
// CHECK: 00000000000000
// CHECK: 10000000000000

{
std::cout << "Passing state from another kernel as argument iteratively (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state{});
for (auto i = 0; i < 4; i++) {
auto counts = cudaq::sample(test_state_param2{}, &state, cudaq::pauli_word{"XX"});
std::cout << "Iteration: " << i << std::endl;
printCounts(counts);
state = cudaq::get_state(test_state_param2{}, &state, cudaq::pauli_word{"XX"});
}
}
// CHECK: Passing state from another kernel as argument iteratively (kernel mode)
// CHECK: Iteration: 0
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 1
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 2
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 3
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11

{
std::cout << "Passing state from another kernel as argument iteratively with vector args (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state{});
auto words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XX"}};
for (auto i = 0; i < 4; i++) {
auto counts = cudaq::sample(test_state_param3{}, &state, words);
std::cout << "Iteration: " << i << std::endl;
printCounts(counts);
state = cudaq::get_state(test_state_param3{}, &state, words);
words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XY"}};
}
}
// CHECK: Passing state from another kernel as argument iteratively with vector args (kernel mode)
// CHECK: Iteration: 0
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 1
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 2
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 3
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11

{
std::cout << "Passing state from another kernel as argument iteratively with vector args with 2 elements (kernel mode)" << std::endl;
auto state = cudaq::get_state(test_init_state{});
auto words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XX"}, cudaq::pauli_word{"YY"}};
auto coeffs = std::vector<double>{1.0, 2.0};
for (auto i = 0; i < 4; i++) {
auto counts = cudaq::sample(test_state_param4{}, &state, coeffs, words);
std::cout << "Iteration: " << i << std::endl;
printCounts(counts);
state = cudaq::get_state(test_state_param4{}, &state, coeffs, words);
words = std::vector<cudaq::pauli_word>{cudaq::pauli_word{"XY"}, cudaq::pauli_word{"YX"}};
coeffs = std::vector<double>{1.0, 2.0};
}
}
// CHECK: Passing state from another kernel as argument iteratively with vector args with 2 elements (kernel mode)
// CHECK: Iteration: 0
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 1
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 2
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
// CHECK: Iteration: 3
// CHECK: 00
// CHECK: 01
// CHECK: 10
// CHECK: 11
}
Loading

0 comments on commit 67b74c1

Please sign in to comment.