From bda56f6e01258a729a13855b096796410c697de2 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Thu, 14 Aug 2025 10:17:55 +0000 Subject: [PATCH 01/10] initial implementation --- .../workflows/config/spelling_allowlist.txt | 1 + CMakeLists.txt | 5 + python/cudaq/dynamics/evolution.py | 2 +- python/extension/CMakeLists.txt | 2 + python/tests/backends/test_Qilimanjaro.py | 30 +++++ runtime/cudaq/platform/CMakeLists.txt | 4 + .../cudaq/platform/qilimanjaro/CMakeLists.txt | 38 ++++++ .../qilimanjaro/QilimanjaroRemoteRESTQPU.cpp | 23 ++++ .../qilimanjaro/QilimanjaroServerHelper.cpp | 117 ++++++++++++++++++ .../qilimanjaro/QilimanjaroServerHelper.h | 67 ++++++++++ .../platform/qilimanjaro/qilimanjaro.yml | 28 +++++ scripts/validate_container.sh | 1 + targettests/lit.site.cfg.py.in | 7 ++ unittests/backends/CMakeLists.txt | 1 + unittests/backends/qilimanjaro/CMakeLists.txt | 25 ++++ .../qilimanjaro/QilimanjaroTester.cpp | 10 ++ 16 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 python/tests/backends/test_Qilimanjaro.py create mode 100644 runtime/cudaq/platform/qilimanjaro/CMakeLists.txt create mode 100644 runtime/cudaq/platform/qilimanjaro/QilimanjaroRemoteRESTQPU.cpp create mode 100644 runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp create mode 100644 runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.h create mode 100644 runtime/cudaq/platform/qilimanjaro/qilimanjaro.yml create mode 100644 unittests/backends/qilimanjaro/CMakeLists.txt create mode 100644 unittests/backends/qilimanjaro/QilimanjaroTester.cpp diff --git a/.github/workflows/config/spelling_allowlist.txt b/.github/workflows/config/spelling_allowlist.txt index dfcb52354df..f97b04ccd67 100644 --- a/.github/workflows/config/spelling_allowlist.txt +++ b/.github/workflows/config/spelling_allowlist.txt @@ -106,6 +106,7 @@ QPUs QPU’s QTX QX +Qilimanjaro Qiskit QuEra QuTiP diff --git a/CMakeLists.txt b/CMakeLists.txt index 961fe1b8318..a40d879824d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,11 @@ if (NOT DEFINED CUDAQ_ENABLE_PASQAL_BACKEND) set(CUDAQ_ENABLE_PASQAL_BACKEND ON CACHE BOOL "Enable building the Pasqal target.") endif() +# Enable Qilimanjaro target by default. +if (NOT DEFINED CUDAQ_ENABLE_QILIMANJARO_BACKEND) + set(CUDAQ_ENABLE_QILIMANJARO_BACKEND ON CACHE BOOL "Enable building the Qilimanjaro target.") +endif() + # Enable Quantum Machines target by default. if (NOT DEFINED CUDAQ_ENABLE_QUANTUM_MACHINES_BACKEND) set(CUDAQ_ENABLE_QUANTUM_MACHINES_BACKEND ON CACHE BOOL "Enable building the Quantum Machines target.") diff --git a/python/cudaq/dynamics/evolution.py b/python/cudaq/dynamics/evolution.py index 974f2b5035a..eaec1cb38f1 100644 --- a/python/cudaq/dynamics/evolution.py +++ b/python/cudaq/dynamics/evolution.py @@ -24,7 +24,7 @@ from .integrator import BaseIntegrator from .schedule import Schedule -analog_targets = ["pasqal", "quera"] +analog_targets = ["pasqal", "qilimanjaro", "quera"] def _taylor_series_expm(op_matrix: NDArray[numpy.complexfloating], diff --git a/python/extension/CMakeLists.txt b/python/extension/CMakeLists.txt index 38880b35ae0..6d4a835a1d9 100644 --- a/python/extension/CMakeLists.txt +++ b/python/extension/CMakeLists.txt @@ -93,6 +93,8 @@ declare_mlir_python_extension(CUDAQuantumPythonSources.Extension ../../runtime/cudaq/platform/orca/OrcaServerHelper.cpp ../../runtime/cudaq/platform/pasqal/PasqalRemoteRESTQPU.cpp ../../runtime/cudaq/platform/pasqal/PasqalServerHelper.cpp + ../../runtime/cudaq/platform/qilimanjaro/QilimanjaroRemoteRESTQPU.cpp + ../../runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp ../../runtime/cudaq/platform/quera/QuEraRemoteRESTQPU.cpp EMBED_CAPI_LINK_LIBS diff --git a/python/tests/backends/test_Qilimanjaro.py b/python/tests/backends/test_Qilimanjaro.py new file mode 100644 index 00000000000..c13645ea18c --- /dev/null +++ b/python/tests/backends/test_Qilimanjaro.py @@ -0,0 +1,30 @@ +# ============================================================================ # +# Copyright (c) 2025 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +import cudaq +import json +import os +import pytest + +skipIfPasqalNotInstalled = pytest.mark.skipif( + not cudaq.has_target("qilimanjaro"), + reason='Could not find `qilimanjaro` in installation' +) + + +@pytest.fixture(scope="session", autouse=True) +def do_something(): + # NOTE: Credentials can be set with environment variables + cudaq.set_target("qilimanjaro") + yield "Running the tests." + cudaq.reset_target() + +# leave for gdb debugging +if __name__ == "__main__": + loc = os.path.abspath(__file__) + pytest.main([loc, "-rP"]) \ No newline at end of file diff --git a/runtime/cudaq/platform/CMakeLists.txt b/runtime/cudaq/platform/CMakeLists.txt index c376a21e858..031b651e243 100644 --- a/runtime/cudaq/platform/CMakeLists.txt +++ b/runtime/cudaq/platform/CMakeLists.txt @@ -24,3 +24,7 @@ endif() if (CUDAQ_ENABLE_PASQAL_BACKEND) add_subdirectory(pasqal) endif() + +if (CUDAQ_ENABLE_QILIMANJARO_BACKEND) + add_subdirectory(qilimanjaro) +endif() diff --git a/runtime/cudaq/platform/qilimanjaro/CMakeLists.txt b/runtime/cudaq/platform/qilimanjaro/CMakeLists.txt new file mode 100644 index 00000000000..422dc53921b --- /dev/null +++ b/runtime/cudaq/platform/qilimanjaro/CMakeLists.txt @@ -0,0 +1,38 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +set(LIBRARY_NAME cudaq-qilimanjaro-qpu) +message(STATUS "Building Qilimanjaro REST QPU.") + +add_library(${LIBRARY_NAME} + SHARED + QilimanjaroRemoteRESTQPU.cpp + QilimanjaroServerHelper.cpp +) + +target_include_directories(${LIBRARY_NAME} PRIVATE . + PUBLIC + $ + $ +) + +target_link_libraries(${LIBRARY_NAME} + PUBLIC + cudaq-operator + cudaq-common + PRIVATE + pthread + cudaq-mlir-runtime + fmt::fmt-header-only + cudaq + cudaq-platform-default +) + +install(TARGETS ${LIBRARY_NAME} DESTINATION lib) + +add_target_config(qilimanjaro) diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroRemoteRESTQPU.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroRemoteRESTQPU.cpp new file mode 100644 index 00000000000..1d1596f66e9 --- /dev/null +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroRemoteRESTQPU.cpp @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2025 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "common/AnalogRemoteRESTQPU.h" + +namespace { + +/// @brief The `QilimanjaroRemoteRESTQPU` is a subtype of QPU that enables the +/// execution of Analog Hamiltonian Program via a REST Client. +class QilimanjaroRemoteRESTQPU : public cudaq::AnalogRemoteRESTQPU { +public: + QilimanjaroRemoteRESTQPU() : AnalogRemoteRESTQPU() {} + QilimanjaroRemoteRESTQPU(QilimanjaroRemoteRESTQPU &&) = delete; + virtual ~QilimanjaroRemoteRESTQPU() = default; +}; +} // namespace + +CUDAQ_REGISTER_TYPE(cudaq::QPU, QilimanjaroRemoteRESTQPU, qilimanjaro) \ No newline at end of file diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp new file mode 100644 index 00000000000..5b150d48d4e --- /dev/null +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2025 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "QilimanjaroServerHelper.h" +#include "common/AnalogHamiltonian.h" +#include "common/Logger.h" + +#include +#include + +namespace cudaq { + +void QilimanjaroServerHelper::initialize(BackendConfig config) { + cudaq::info("Initialize Qilimanjaro's SpeQtrum."); + + // Hard-coded for now. + const std::string MACHINE = "CUDA_DYNAMICS"; + + cudaq::info("Running on device {}", MACHINE); + + if (!config.contains("machine")) + config["machine"] = MACHINE; + + if (!config["shots"].empty()) + setShots(std::stoul(config["shots"])); + + parseConfigForCommonParams(config); + + backendConfig = std::move(config); +} + +RestHeaders QilimanjaroServerHelper::getHeaders() { + std::string token; + + if (auto auth_token = std::getenv("QILIMANJARO_AUTH_TOKEN")) + token = "Bearer " + std::string(auth_token); + else + token = "Bearer "; + + std::map headers{ + {"Authorization", token}, + {"Content-Type", "application/json"}, + {"User-Agent", "cudaq/0.12.0"}, + {"Connection", "keep-alive"}, + {"Accept", "*/*"}}; + + return headers; +} + +ServerJobPayload +QilimanjaroServerHelper::createJob(std::vector &circuitCodes) { + std::vector tasks; + + for (auto &circuitCode : circuitCodes) { + ServerMessage message; + message["machine"] = backendConfig.at("machine"); + message["shots"] = shots; + message["project_id"] = backendConfig.at("project_id"); + message["sequence"] = nlohmann::json::parse(circuitCode.code); + tasks.push_back(message); + } + + cudaq::info("Created job payload for Qilimanjaro, targeting device {}", + backendConfig.at("machine")); + + // Return a tuple containing the job path, headers, and the job message + return std::make_tuple(speqtrumApiUrl + "/execute", getHeaders(), tasks); +} + +std::string QilimanjaroServerHelper::extractJobId(ServerMessage &postResponse) { + return postResponse["data"]["id"].get(); +} + +std::string QilimanjaroServerHelper::constructGetJobPath(std::string &jobId) { + return speqtrumApiUrl + "/jobs/" + jobId; +} + +std::string +QilimanjaroServerHelper::constructGetJobPath(ServerMessage &postResponse) { + return speqtrumApiUrl + "/jobs/" + postResponse["data"]["id"].get(); +} + +bool QilimanjaroServerHelper::jobIsDone(ServerMessage &getJobResponse) { + std::unordered_set terminal_states = {"COMPLETED", "ERROR", "CANCELED"}; + auto jobStatus = getJobResponse["data"]["status"].get(); + return terminal_states.find(jobStatus) != terminal_states.end(); +} + +sample_result QilimanjaroServerHelper::processResults(ServerMessage &postJobResponse, + std::string &jobId) { + auto status = postJobResponse["data"]["status"].get(); + if (status != "COMPLETED") + throw std::runtime_error("Job status: " + status); + + std::vector results; + auto jobs = postJobResponse["data"]["result"]; + for (auto &job : jobs) { + std::unordered_map result; + for (auto &[bitstring, count] : job.items()) { + auto r_bitstring = bitstring; + result[r_bitstring] = count; + } + results.push_back(ExecutionResult(result)); + } + + return sample_result(results); +} + +} // namespace cudaq + +// Register the Qilimanjaro server helper in the CUDA-Q server helper factory +CUDAQ_REGISTER_TYPE(cudaq::ServerHelper, cudaq::QilimanjaroServerHelper, qilimanjaro) \ No newline at end of file diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.h b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.h new file mode 100644 index 00000000000..460b46edbc5 --- /dev/null +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.h @@ -0,0 +1,67 @@ +/****************************************************************-*- C++ -*-**** + * Copyright (c) 2025 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "common/ServerHelper.h" +#include "nlohmann/json.hpp" + +namespace cudaq { + +class QilimanjaroServerHelper : public ServerHelper { +protected: + /// @brief Server helper implementation for communicating with the REST API of + /// Qilimanjaro's SpeQtrum platform. + const std::string speqtrumApiUrl = "https://qilimanjaro.ddns.net/public-api/api/v1"; + +public: + /// @brief Returns the name of the server helper. + const std::string name() const override { return "qilimanjaro"; } + + /// @brief Initializes the server helper with the provided backend + /// configuration. + void initialize(BackendConfig config) override; + + /// @brief Return the POST/GET required headers. + /// @return + RestHeaders getHeaders() override; + + /// @brief Creates a quantum computation job using the provided kernel + /// executions and returns the corresponding payload. + ServerJobPayload + createJob(std::vector &circuitCodes) override; + + /// @brief Extract the job id from the server response from posting the job. + std::string extractJobId(ServerMessage &postResponse) override; + + /// @brief Get the specific path required to retrieve job results. Construct + /// specifically from the job id. + std::string constructGetJobPath(std::string &jobId) override; + + /// @brief Get the specific path required to retrieve job results. Construct + /// from the full server response message. + std::string constructGetJobPath(ServerMessage &postResponse) override; + + /// @brief Get the jobs results polling interval. + /// @return + std::chrono::microseconds + nextResultPollingInterval(ServerMessage &postResponse) override { + return std::chrono::seconds(1); + } + + /// @brief Return true if the job is done. + bool jobIsDone(ServerMessage &getJobResponse) override; + + /// @brief Given a successful job and the success response, + /// retrieve the results and map them to a sample_result. + /// @param postJobResponse + /// @param jobId + /// @return + sample_result processResults(ServerMessage &postJobResponse, + std::string &jobId) override; +}; + +} // namespace cudaq diff --git a/runtime/cudaq/platform/qilimanjaro/qilimanjaro.yml b/runtime/cudaq/platform/qilimanjaro/qilimanjaro.yml new file mode 100644 index 00000000000..b7e06cc9d4c --- /dev/null +++ b/runtime/cudaq/platform/qilimanjaro/qilimanjaro.yml @@ -0,0 +1,28 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +name: qilimanjaro +description: "CUDA-Q target for qilimanjaro." +config: + # Tell DefaultQuantumPlatform what QPU subtype to use + platform-qpu: qilimanjaro + # Add the qilimanjaro-qpu library to the link list + link-libs: ["-lcudaq-qilimanjaro-qpu"] + # Allow evolve API in C++ + preprocessor-defines: ["-D CUDAQ_ANALOG_TARGET"] + # Library mode is only for simulators, physical backends must turn this off + library-mode: false + # Tell NVQ++ to generate glue code to set the target backend name + gen-target-backend: true + +target-arguments: + - key: machine + required: false + type: string + platform-arg: machine + help-string: "Specify the Qilimanjaro machine." diff --git a/scripts/validate_container.sh b/scripts/validate_container.sh index fd101dbbb50..5435756a269 100644 --- a/scripts/validate_container.sh +++ b/scripts/validate_container.sh @@ -84,6 +84,7 @@ available_backends=`\ if [ "${qpu}" != "remote_rest" ] && [ "${qpu}" != "NvcfSimulatorQPU" ] \ && [ "${qpu}" != "fermioniq" ] && [ "${qpu}" != "orca" ] \ && [ "${qpu}" != "pasqal" ] && [ "${qpu}" != "quera" ] \ + && [ "${qpu}" != "qilimanjaro" ] \ && ($gpu_available || [ -z "$gpus" ] || [ "${gpus,,}" == "false" ]); then \ basename $file | cut -d "." -f 1; \ fi; \ diff --git a/targettests/lit.site.cfg.py.in b/targettests/lit.site.cfg.py.in index 0809719dc83..a866c693704 100644 --- a/targettests/lit.site.cfg.py.in +++ b/targettests/lit.site.cfg.py.in @@ -57,6 +57,13 @@ if cmake_boolvar_to_bool(config.cudaq_backends_pasqal): else: config.substitutions.append(('%pasqal_avail', 'false')) +config.cudaq_backends_qilimanjaro = "@CUDAQ_ENABLE_QILIMANJARO_BACKEND@" +if cmake_boolvar_to_bool(config.cudaq_backends_qilimanjaro): + config.available_features.add('qilimanjaro') + config.substitutions.append(('%qilimanjaro_avail', 'true')) +else: + config.substitutions.append(('%qilimanjaro_avail', 'false')) + config.cudaq_backends_quantum_machines = "@CUDAQ_ENABLE_QUANTUM_MACHINES_BACKEND@" if cmake_boolvar_to_bool(config.cudaq_backends_quantum_machines): config.available_features.add('quantum_machines') diff --git a/unittests/backends/CMakeLists.txt b/unittests/backends/CMakeLists.txt index 008c97c1104..550d8d5022b 100644 --- a/unittests/backends/CMakeLists.txt +++ b/unittests/backends/CMakeLists.txt @@ -22,3 +22,4 @@ endif() add_subdirectory(pasqal) add_subdirectory(qpp_observe) add_subdirectory(quera) +add_subdirectory(qilimanjaro) diff --git a/unittests/backends/qilimanjaro/CMakeLists.txt b/unittests/backends/qilimanjaro/CMakeLists.txt new file mode 100644 index 00000000000..b8e7a38dac7 --- /dev/null +++ b/unittests/backends/qilimanjaro/CMakeLists.txt @@ -0,0 +1,25 @@ +# ============================================================================ # +# Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # +# All rights reserved. # +# # +# This source code and the accompanying materials are made available under # +# the terms of the Apache License 2.0 which accompanies this distribution. # +# ============================================================================ # + +add_executable(test_pasqal QilimanjaroTester.cpp) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) + target_link_options(test_qilimanjaro PRIVATE -Wl,--no-as-needed) +endif() + +target_include_directories(test_qilimanjaro PRIVATE ../..) + +target_link_libraries(test_qilimanjaro + PRIVATE + fmt::fmt-header-only + cudaq + cudaq-common + gtest_main +) + +gtest_discover_tests(test_qilimanjaro) diff --git a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp new file mode 100644 index 00000000000..fd83aa2f30f --- /dev/null +++ b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright (c) 2025 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#include "CUDAQTestUtils.h" +#include "common/AnalogHamiltonian.h" \ No newline at end of file From c8817c9fa2c4897d7c623b997f76754bf2d1f4cf Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Thu, 14 Aug 2025 10:57:04 +0000 Subject: [PATCH 02/10] fix typo --- unittests/backends/qilimanjaro/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/backends/qilimanjaro/CMakeLists.txt b/unittests/backends/qilimanjaro/CMakeLists.txt index b8e7a38dac7..940851cb1fc 100644 --- a/unittests/backends/qilimanjaro/CMakeLists.txt +++ b/unittests/backends/qilimanjaro/CMakeLists.txt @@ -6,7 +6,7 @@ # the terms of the Apache License 2.0 which accompanies this distribution. # # ============================================================================ # -add_executable(test_pasqal QilimanjaroTester.cpp) +add_executable(test_qilimanjaro QilimanjaroTester.cpp) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) target_link_options(test_qilimanjaro PRIVATE -Wl,--no-as-needed) From a6859a82ea6766c73edc2a3e3f585a1ae2ba06bc Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Wed, 20 Aug 2025 08:10:38 +0000 Subject: [PATCH 03/10] fix typo --- python/tests/backends/test_Qilimanjaro.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tests/backends/test_Qilimanjaro.py b/python/tests/backends/test_Qilimanjaro.py index c13645ea18c..07761d3b160 100644 --- a/python/tests/backends/test_Qilimanjaro.py +++ b/python/tests/backends/test_Qilimanjaro.py @@ -11,7 +11,7 @@ import os import pytest -skipIfPasqalNotInstalled = pytest.mark.skipif( +skipIfQilimanjaroNotInstalled = pytest.mark.skipif( not cudaq.has_target("qilimanjaro"), reason='Could not find `qilimanjaro` in installation' ) From fdd620d7730500d7b59d7760577b42a6d0d62104 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Tue, 23 Sep 2025 10:16:49 +0200 Subject: [PATCH 04/10] fix typo --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b89ab67b427..327788a3c35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,7 @@ endif() # Enable Qilimanjaro target by default. if (NOT DEFINED CUDAQ_ENABLE_QILIMANJARO_BACKEND) set(CUDAQ_ENABLE_QILIMANJARO_BACKEND ON CACHE BOOL "Enable building the Qilimanjaro target.") +endif() # Enable Quantum Circuits, Inc. (QCI) target by default. if (NOT DEFINED CUDAQ_ENABLE_QCI_BACKEND) From 5d5b04166edef88d026f866e58e8a24a1a27d063 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Tue, 23 Sep 2025 10:22:14 +0200 Subject: [PATCH 05/10] DCO Remediation Commit for Vyron Vasileiadis I, Vyron Vasileiadis , hereby add my Signed-off-by to this commit: bda56f6e01258a729a13855b096796410c697de2 I, Vyron Vasileiadis , hereby add my Signed-off-by to this commit: c8817c9fa2c4897d7c623b997f76754bf2d1f4cf I, Vyron Vasileiadis , hereby add my Signed-off-by to this commit: a6859a82ea6766c73edc2a3e3f585a1ae2ba06bc Signed-off-by: Vyron Vasileiadis --- .../cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp index 5b150d48d4e..9d5bc61c2c3 100644 --- a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp @@ -26,8 +26,8 @@ void QilimanjaroServerHelper::initialize(BackendConfig config) { if (!config.contains("machine")) config["machine"] = MACHINE; - if (!config["shots"].empty()) - setShots(std::stoul(config["shots"])); + if (!config["nshots"].empty()) + setShots(std::stoul(config["nshots"])); parseConfigForCommonParams(config); From d038a208a53fff4237e0c95ace384c51200c9de9 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Tue, 23 Sep 2025 10:38:12 +0200 Subject: [PATCH 06/10] DCO Remediation Commit for Vyron Vasileiadis I, Vyron Vasileiadis , hereby add my Signed-off-by to this commit: fdd620d7730500d7b59d7760577b42a6d0d62104 Signed-off-by: Vyron Vasileiadis --- runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp index 9d5bc61c2c3..99b677fec7c 100644 --- a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp @@ -60,7 +60,6 @@ QilimanjaroServerHelper::createJob(std::vector &circuitCodes) { ServerMessage message; message["machine"] = backendConfig.at("machine"); message["shots"] = shots; - message["project_id"] = backendConfig.at("project_id"); message["sequence"] = nlohmann::json::parse(circuitCode.code); tasks.push_back(message); } From 72eeeb2bb7d6fdeac1773b381963a69bb3dabfa4 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Thu, 9 Oct 2025 14:35:41 +0200 Subject: [PATCH 07/10] Update QilimanjaroServerHelper --- .../qilimanjaro/QilimanjaroServerHelper.cpp | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp index 99b677fec7c..fa763bbf027 100644 --- a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp @@ -19,7 +19,7 @@ void QilimanjaroServerHelper::initialize(BackendConfig config) { cudaq::info("Initialize Qilimanjaro's SpeQtrum."); // Hard-coded for now. - const std::string MACHINE = "CUDA_DYNAMICS"; + const std::string MACHINE = "radagast"; cudaq::info("Running on device {}", MACHINE); @@ -55,12 +55,13 @@ RestHeaders QilimanjaroServerHelper::getHeaders() { ServerJobPayload QilimanjaroServerHelper::createJob(std::vector &circuitCodes) { std::vector tasks; - + // TODO: circuitCodes needs to change to the time evolution JSON for (auto &circuitCode : circuitCodes) { ServerMessage message; - message["machine"] = backendConfig.at("machine"); + message["device_code"] = backendConfig.at("machine"); message["shots"] = shots; - message["sequence"] = nlohmann::json::parse(circuitCode.code); + message["job_type"] = "analog"; + message["payload"] = nlohmann::json::parse(circuitCode.code); tasks.push_back(message); } @@ -72,40 +73,35 @@ QilimanjaroServerHelper::createJob(std::vector &circuitCodes) { } std::string QilimanjaroServerHelper::extractJobId(ServerMessage &postResponse) { - return postResponse["data"]["id"].get(); + return postResponse["id"].get(); } std::string QilimanjaroServerHelper::constructGetJobPath(std::string &jobId) { - return speqtrumApiUrl + "/jobs/" + jobId; + return speqtrumApiUrl + "/jobs/" + jobId + "?result=true"; } std::string QilimanjaroServerHelper::constructGetJobPath(ServerMessage &postResponse) { - return speqtrumApiUrl + "/jobs/" + postResponse["data"]["id"].get(); + auto jobId = extractJobId(postResponse); + return constructGetJobPath(jobId); } bool QilimanjaroServerHelper::jobIsDone(ServerMessage &getJobResponse) { - std::unordered_set terminal_states = {"COMPLETED", "ERROR", "CANCELED"}; - auto jobStatus = getJobResponse["data"]["status"].get(); + std::unordered_set terminal_states = {"completed", "error", "canceled", "timeout"}; + auto jobStatus = getJobResponse["status"].get(); return terminal_states.find(jobStatus) != terminal_states.end(); } sample_result QilimanjaroServerHelper::processResults(ServerMessage &postJobResponse, - std::string &jobId) { - auto status = postJobResponse["data"]["status"].get(); - if (status != "COMPLETED") - throw std::runtime_error("Job status: " + status); - + std::string &jobId) { + auto jobStatus = postJobResponse["status"].get(); + if (jobStatus != "completed") + throw std::runtime_error("Job status: " + jobStatus); + + auto job_result = postJobResponse["result"]; + + // TODO: Use EvolveResults instead. Need to change method signature. std::vector results; - auto jobs = postJobResponse["data"]["result"]; - for (auto &job : jobs) { - std::unordered_map result; - for (auto &[bitstring, count] : job.items()) { - auto r_bitstring = bitstring; - result[r_bitstring] = count; - } - results.push_back(ExecutionResult(result)); - } return sample_result(results); } From 686aa8bb147db93a60ede1c96993cab74837acf1 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sun, 12 Oct 2025 21:43:56 +0200 Subject: [PATCH 08/10] update QilimanjaroTester --- .../qilimanjaro/QilimanjaroTester.cpp | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp index fd83aa2f30f..1de5701796a 100644 --- a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp +++ b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp @@ -7,4 +7,70 @@ ******************************************************************************/ #include "CUDAQTestUtils.h" -#include "common/AnalogHamiltonian.h" \ No newline at end of file +#include "common/AnalogHamiltonian.h" + +const std::string sampleTimeEvolutionPayload = R"( + { + "type": "time_evolution", + "payload": { + "hamiltonian": { + "Hinit": { + "X0": 0.8, + "X1": 0.6, + "X0X1": 0.4 + }, + "Hinter": { + "Z0": 1.0, + "Z1": 0.9, + "Z0Z1": 0.5 + }, + "Hfinal": { + "Z0": 1.2, + "Z1": 1.0, + "Z0Z1": 0.7 + } + }, + "schedules": [ + { + "Hinit": [1.0, 0.75, 0.5, 0.25, 0.0], + "Hinter": [0.0, 0.25, 0.5, 0.75, 1.0], + "Hfinal": [0.0, 0.0, 0.0, 0.0, 0.0] + }, + { + "Hinit": [0.0, 0.0, 0.0, 0.0, 0.0], + "Hinter": [1.0, 0.75, 0.5, 0.25, 0.0], + "Hfinal": [0.0, 0.25, 0.5, 0.75, 1.0] + } + ], + "observables": [ + { + "Z0": 1.0, + "Z1": 0.8, + "Z0Z1": 0.6 + }, + { + "X0": 0.9, + "X1": 0.7, + "X0X1": 0.5 + } + ], + "initial_state": [ + {"real": 0.7071, "imag": 0.0}, + {"real": 0.0, "imag": 0.0}, + {"real": 0.0, "imag": 0.0}, + {"real": 0.7071, "imag": 0.0} + ] + } + } +)"; + +CUDAQ_TEST(QilimanjaroTester, checkTimeEvolutionJson) { + cudaq::spin_op Hinit = 0.8 * cudaq::spin::x(0) + 0.6 * cudaq::spin::x(1) + 0.4 * cudaq::spin::x(0) * cudaq::spin::x(1); + cudaq::spin_op Hinter = 1.0 * cudaq::spin::z(0) + 0.9 * cudaq::spin::z(1) + 0.5 * cudaq::spin::z(0) * cudaq::spin::z(1); + cudaq::spin_op Hfinal = 1.2 * cudaq::spin::z(0) + 1.0 * cudaq::spin::z(1) + 0.7 * cudaq::spin::z(0) * cudaq::spin::z(1); + + std::vector> psi_data = { + {0.7071, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.7071, 0.0} + }; + cudaq::state psi = cudaq::state::from_data(psi_data); +} \ No newline at end of file From 475c79fc6fd0aca96d52bc4658d06c1a8f1eb335 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Mon, 13 Oct 2025 09:12:58 +0200 Subject: [PATCH 09/10] update QilimanjaroTester --- .../qilimanjaro/QilimanjaroTester.cpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp index 1de5701796a..391611f47ff 100644 --- a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp +++ b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp @@ -65,12 +65,38 @@ const std::string sampleTimeEvolutionPayload = R"( )"; CUDAQ_TEST(QilimanjaroTester, checkTimeEvolutionJson) { + // Define Hamiltonians cudaq::spin_op Hinit = 0.8 * cudaq::spin::x(0) + 0.6 * cudaq::spin::x(1) + 0.4 * cudaq::spin::x(0) * cudaq::spin::x(1); cudaq::spin_op Hinter = 1.0 * cudaq::spin::z(0) + 0.9 * cudaq::spin::z(1) + 0.5 * cudaq::spin::z(0) * cudaq::spin::z(1); cudaq::spin_op Hfinal = 1.2 * cudaq::spin::z(0) + 1.0 * cudaq::spin::z(1) + 0.7 * cudaq::spin::z(0) * cudaq::spin::z(1); - std::vector> psi_data = { + // Define initial state + std::vector> initial_state_data = { {0.7071, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.7071, 0.0} }; - cudaq::state psi = cudaq::state::from_data(psi_data); + cudaq::state initial_state = cudaq::state::from_data(initial_state_data); + + // Define observables + std::vector observables = { + 1.0 * cudaq::spin::z(0) + 0.7 * cudaq::spin::z(1) + 0.6 * cudaq::spin::z(0) * cudaq::spin::z(1), + 0.9 * cudaq::spin::x(0) + 0.7 * cudaq::spin::x(1) + 0.5 * cudaq::spin::x(0) * cudaq::spin::x(1) + }; + + // Define schedules (Is there any cudaq class?) + std::vector>> schedules = { + { + {"Hinit", {1.0, 0.75, 0.5, 0.25, 0.0}}, + {"Hinter", {0.0, 0.25, 0.5, 0.75, 1.0}}, + {"Hfinal", {0.0, 0.0, 0.0, 0.0, 0.0}} + }, + { + {"Hinit", {0.0, 0.0, 0.0, 0.0, 0.0}}, + {"Hinter", {1.0, 0.75, 0.5, 0.25, 0.0}}, + {"Hfinal", {0.0, 0.25, 0.5, 0.75, 1.0}} + } + }; + + // TODO: How will we construct the payload and which is the class we should parse into? + + auto refPayload = nlohmann::json::parse(sampleTimeEvolutionPayload); } \ No newline at end of file From 1a450987564e2f40283e246aa988d02757c7e127 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Mon, 13 Oct 2025 09:47:40 +0200 Subject: [PATCH 10/10] update QilimanjaroTester --- .../cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp | 6 +++--- unittests/backends/qilimanjaro/QilimanjaroTester.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp index fa763bbf027..674a2846c3d 100644 --- a/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp +++ b/runtime/cudaq/platform/qilimanjaro/QilimanjaroServerHelper.cpp @@ -45,7 +45,7 @@ RestHeaders QilimanjaroServerHelper::getHeaders() { std::map headers{ {"Authorization", token}, {"Content-Type", "application/json"}, - {"User-Agent", "cudaq/0.12.0"}, + {"User-Agent", "cudaq/0.12.0"}, // TODO: How to get version dynamically? {"Connection", "keep-alive"}, {"Accept", "*/*"}}; @@ -55,7 +55,7 @@ RestHeaders QilimanjaroServerHelper::getHeaders() { ServerJobPayload QilimanjaroServerHelper::createJob(std::vector &circuitCodes) { std::vector tasks; - // TODO: circuitCodes needs to change to the time evolution JSON + // TODO: circuitCodes needs to change to the Time Evolution JSON for (auto &circuitCode : circuitCodes) { ServerMessage message; message["device_code"] = backendConfig.at("machine"); @@ -100,7 +100,7 @@ sample_result QilimanjaroServerHelper::processResults(ServerMessage &postJobResp auto job_result = postJobResponse["result"]; - // TODO: Use EvolveResults instead. Need to change method signature. + // TODO: We need a new method signature with EvolveResults instead. std::vector results; return sample_result(results); diff --git a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp index 391611f47ff..d4e1aae9b97 100644 --- a/unittests/backends/qilimanjaro/QilimanjaroTester.cpp +++ b/unittests/backends/qilimanjaro/QilimanjaroTester.cpp @@ -13,7 +13,7 @@ const std::string sampleTimeEvolutionPayload = R"( { "type": "time_evolution", "payload": { - "hamiltonian": { + "hamiltonians": { "Hinit": { "X0": 0.8, "X1": 0.6,