From fd0b0b9cbc317fcb06215ad4760b2f7f4b7bb8d5 Mon Sep 17 00:00:00 2001 From: Ben Howe Date: Mon, 25 Nov 2024 23:59:03 +0000 Subject: [PATCH 1/2] Follow-up to #2394 - handle remote REST QPU also Signed-off-by: Ben Howe --- runtime/common/BaseRemoteRESTQPU.h | 7 +++---- runtime/common/BraketExecutor.h | 4 ++-- runtime/common/Executor.cpp | 6 +++--- runtime/common/Executor.h | 3 ++- runtime/common/Future.cpp | 6 +++++- runtime/common/Future.h | 8 ++++++++ .../default/rest/helpers/braket/BraketExecutor.cpp | 3 ++- runtime/cudaq/platform/orca/OrcaExecutor.h | 4 ++-- 8 files changed, 27 insertions(+), 14 deletions(-) diff --git a/runtime/common/BaseRemoteRESTQPU.h b/runtime/common/BaseRemoteRESTQPU.h index f8e67601d7..625bab9bdc 100644 --- a/runtime/common/BaseRemoteRESTQPU.h +++ b/runtime/common/BaseRemoteRESTQPU.h @@ -626,6 +626,7 @@ class BaseRemoteRESTQPU : public cudaq::QPU { localShots = executionContext->shots; executor->setShots(localShots); + bool isObserve = executionContext && executionContext->name == "observe"; // If emulation requested, then just grab the function // and invoke it with the simulator @@ -638,7 +639,7 @@ class BaseRemoteRESTQPU : public cudaq::QPU { // Launch the execution of the simulated jobs asynchronously future = cudaq::details::future(std::async( std::launch::async, - [&, codes, localShots, kernelName, seed, + [&, codes, localShots, kernelName, seed, isObserve, reorderIdx = executionContext->reorderIdx, localJIT = std::move(jitEngines)]() mutable -> cudaq::sample_result { std::vector results; @@ -679,8 +680,6 @@ class BaseRemoteRESTQPU : public cudaq::QPU { } } - bool isObserve = - executionContext && executionContext->name == "observe"; for (std::size_t i = 0; i < codes.size(); i++) { cudaq::ExecutionContext context("sample", localShots); context.reorderIdx = reorderIdx; @@ -712,7 +711,7 @@ class BaseRemoteRESTQPU : public cudaq::QPU { // Allow developer to disable remote sending (useful for debugging IR) if (getEnvBool("DISABLE_REMOTE_SEND", false)) return; - future = executor->execute(codes); + future = executor->execute(codes, isObserve); } // Keep this asynchronous if requested diff --git a/runtime/common/BraketExecutor.h b/runtime/common/BraketExecutor.h index 4c9ff33802..d9f9ba6a37 100644 --- a/runtime/common/BraketExecutor.h +++ b/runtime/common/BraketExecutor.h @@ -74,8 +74,8 @@ class BraketExecutor : public Executor { ~BraketExecutor() = default; /// @brief Execute the provided Braket task - details::future - execute(std::vector &codesToExecute) override; + details::future execute(std::vector &codesToExecute, + bool isObserve) override; /// @brief Set the server helper void setServerHelper(ServerHelper *helper) override; diff --git a/runtime/common/Executor.cpp b/runtime/common/Executor.cpp index c6eea22b4e..5d469670de 100644 --- a/runtime/common/Executor.cpp +++ b/runtime/common/Executor.cpp @@ -10,8 +10,8 @@ #include "common/Logger.h" namespace cudaq { -details::future -Executor::execute(std::vector &codesToExecute) { +details::future Executor::execute(std::vector &codesToExecute, + bool isObserve) { serverHelper->setShots(shots); @@ -53,7 +53,7 @@ Executor::execute(std::vector &codesToExecute) { config.insert({"shots", std::to_string(shots)}); std::string name = serverHelper->name(); - return details::future(ids, name, config); + return details::future(ids, name, config, isObserve); } } // namespace cudaq diff --git a/runtime/common/Executor.h b/runtime/common/Executor.h index 451e0bbdfb..10f552ffe0 100644 --- a/runtime/common/Executor.h +++ b/runtime/common/Executor.h @@ -41,7 +41,8 @@ class Executor : public registry::RegisteredType { /// @brief Execute the provided quantum codes and return a future object /// The caller can make this synchronous by just immediately calling .get(). - virtual details::future execute(std::vector &codesToExecute); + virtual details::future execute(std::vector &codesToExecute, + bool isObserve = false); }; } // namespace cudaq diff --git a/runtime/common/Future.cpp b/runtime/common/Future.cpp index 95f3239efd..9f6216c7fb 100644 --- a/runtime/common/Future.cpp +++ b/runtime/common/Future.cpp @@ -43,7 +43,7 @@ sample_result future::get() { // If there are multiple jobs, this is likely a spin_op. // If so, use the job name instead of the global register. - if (jobs.size() > 1) { + if (isObserve || jobs.size() > 1) { results.emplace_back(c.to_map(), id.second); results.back().sequentialData = c.sequential_data(); } else { @@ -75,6 +75,7 @@ future &future::operator=(future &other) { jobs = other.jobs; qpuName = other.qpuName; serverConfig = other.serverConfig; + isObserve = other.isObserve; if (other.wrapsFutureSampling) { wrapsFutureSampling = true; inFuture = std::move(other.inFuture); @@ -86,6 +87,7 @@ future &future::operator=(future &&other) { jobs = other.jobs; qpuName = other.qpuName; serverConfig = other.serverConfig; + isObserve = other.isObserve; if (other.wrapsFutureSampling) { wrapsFutureSampling = true; inFuture = std::move(other.inFuture); @@ -102,6 +104,7 @@ std::ostream &operator<<(std::ostream &os, future &f) { j["jobs"] = f.jobs; j["qpu"] = f.qpuName; j["config"] = f.serverConfig; + j["isObserve"] = f.isObserve; os << j.dump(4); return os; } @@ -117,6 +120,7 @@ std::istream &operator>>(std::istream &is, future &f) { f.jobs = j["jobs"].get>(); f.qpuName = j["qpu"].get(); f.serverConfig = j["config"].get>(); + f.isObserve = j["isObserve"].get(); return is; } diff --git a/runtime/common/Future.h b/runtime/common/Future.h index 2c499064d2..5cc8a8df5e 100644 --- a/runtime/common/Future.h +++ b/runtime/common/Future.h @@ -49,6 +49,9 @@ class future { std::future inFuture; bool wrapsFutureSampling = false; + /// @brief Whether or not this is in support of an "observe" call + bool isObserve = false; + public: /// @brief The constructor future() = default; @@ -69,6 +72,11 @@ class future { std::map &config) : jobs(_jobs), qpuName(qpuNameIn), serverConfig(config) {} + future(std::vector &_jobs, std::string &qpuNameIn, + std::map &config, bool isObserve) + : jobs(_jobs), qpuName(qpuNameIn), serverConfig(config), + isObserve(isObserve) {} + future &operator=(future &other); future &operator=(future &&other); diff --git a/runtime/cudaq/platform/default/rest/helpers/braket/BraketExecutor.cpp b/runtime/cudaq/platform/default/rest/helpers/braket/BraketExecutor.cpp index d99549cf03..2f1180587a 100644 --- a/runtime/cudaq/platform/default/rest/helpers/braket/BraketExecutor.cpp +++ b/runtime/cudaq/platform/default/rest/helpers/braket/BraketExecutor.cpp @@ -161,7 +161,8 @@ ServerJobPayload BraketExecutor::checkHelperAndCreateJob( } details::future -BraketExecutor::execute(std::vector &codesToExecute) { +BraketExecutor::execute(std::vector &codesToExecute, + bool isObserve) { auto [dummy1, dummy2, messages] = checkHelperAndCreateJob(codesToExecute); std::string const defaultBucket = defaultBucketFuture.get(); diff --git a/runtime/cudaq/platform/orca/OrcaExecutor.h b/runtime/cudaq/platform/orca/OrcaExecutor.h index 739d20faa9..990da236c4 100644 --- a/runtime/cudaq/platform/orca/OrcaExecutor.h +++ b/runtime/cudaq/platform/orca/OrcaExecutor.h @@ -17,8 +17,8 @@ namespace cudaq { /// API. class OrcaExecutor : public Executor { public: - details::future - execute(std::vector &codesToExecute) override { + details::future execute(std::vector &codesToExecute, + bool isObserve) override { throw std::runtime_error( "ORCA backend does not support executing arbitrary kernels"); } From d004ac0449573c9d83413b3f535338c01f64535d Mon Sep 17 00:00:00 2001 From: Ben Howe Date: Tue, 26 Nov 2024 17:45:16 +0000 Subject: [PATCH 2/2] Updates per offline code review Signed-off-by: Ben Howe --- runtime/common/BaseRemoteRESTQPU.h | 7 +++---- runtime/common/Future.cpp | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/runtime/common/BaseRemoteRESTQPU.h b/runtime/common/BaseRemoteRESTQPU.h index 625bab9bdc..d79286e18c 100644 --- a/runtime/common/BaseRemoteRESTQPU.h +++ b/runtime/common/BaseRemoteRESTQPU.h @@ -650,7 +650,7 @@ class BaseRemoteRESTQPU : public cudaq::QPU { bool hasConditionals = cudaq::kernelHasConditionalFeedback(kernelName); - if (hasConditionals && codes.size() > 1) + if (hasConditionals && isObserve) throw std::runtime_error("error: spin_ops not yet supported with " "kernels containing conditionals"); if (hasConditionals) { @@ -687,9 +687,8 @@ class BaseRemoteRESTQPU : public cudaq::QPU { invokeJITKernelAndRelease(localJIT[i], kernelName); cudaq::getExecutionManager()->resetExecutionContext(); - // If there are multiple codes, this is likely a spin_op. - // If so, use the code name instead of the global register. - if (isObserve || (codes.size() > 1)) { + if (isObserve) { + // Use the code name instead of the global register. results.emplace_back(context.result.to_map(), codes[i].name); results.back().sequentialData = context.result.sequential_data(); diff --git a/runtime/common/Future.cpp b/runtime/common/Future.cpp index 9f6216c7fb..56c8da888c 100644 --- a/runtime/common/Future.cpp +++ b/runtime/common/Future.cpp @@ -41,9 +41,8 @@ sample_result future::get() { } auto c = serverHelper->processResults(resultResponse, id.first); - // If there are multiple jobs, this is likely a spin_op. - // If so, use the job name instead of the global register. - if (isObserve || jobs.size() > 1) { + if (isObserve) { + // Use the job name instead of the global register. results.emplace_back(c.to_map(), id.second); results.back().sequentialData = c.sequential_data(); } else {