Repository: NVIDIA/cuda-quantum
Pull request #2704: Support Rydberg Hamiltonian in C++ Evolve API
Author: login: nvidia-dobri
Labels: name: enhancement
description: New feature or request
Created: 2025-03-06T20:36:24Z | Merged: 2025-03-08T01:18:22Z

This enables Rydberg Hamiltonian evolution through analog quantum backends, currently QuEra and Pasqal. Authentication unique to each platform is required to run the examples.

QuEra requires valid AWS credentials with Braket access:
```
nvq++ --target quera 'quera_basic.cpp' -o out.x && CUDAQ_LOG_LEVEL=info ./out.x
nvq++ --target quera 'quera_intro.cpp' -o out.x && CUDAQ_LOG_LEVEL=info ./out.x
```

Pasqal requires env variables:
* `PASQAL_PROJECT_ID` from [Pasqal Cloud](https://portal.pasqal.cloud/)
* `PASQAL_AUTH_TOKEN` obtained with `pasqal_cloud` python library.
```
nvq++ --target pasqal 'pasqal.cpp' -o out.x && CUDAQ_LOG_LEVEL=info ./out.x
```


Diff:
diff --git a/docs/sphinx/targets/cpp/pasqal.cpp b/docs/sphinx/targets/cpp/pasqal.cpp
new file mode 100644
index 00000000000..aa86dc9a114
--- /dev/null
+++ b/docs/sphinx/targets/cpp/pasqal.cpp
@@ -0,0 +1,70 @@
+// Compile and run with:
+// ```
+// nvq++ --target pasqal pasqal.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials (PASQAL_AUTH_TOKEN, PASQAL_PROJECT_ID)
+// have been set. To set PASQAL_AUTH_TOKEN from Pasqal Cloud username and
+// password, use pasqal_auth.py in this folder.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <cmath>
+#include <map>
+#include <vector>
+
+// This example illustrates how to use Pasqal's EMU_MPS emulator over Pasqal's
+// cloud via CUDA-Q. Contact Pasqal at help@pasqal.com or through
+// https://community.pasqal.com for assistance.
+
+int main() {
+  // Topology initialization
+  const double a = 5e-6;
+  std::vector<std::pair<double, double>> register_sites;
+  register_sites.push_back(std::make_pair(a, 0.0));
+  register_sites.push_back(std::make_pair(2 * a, 0.0));
+  register_sites.push_back(std::make_pair(3 * a, 0.0));
+
+  // Simulation Timing
+  const double time_ramp = 0.000001; // seconds
+  const double time_max = 0.000003;  // seconds
+  const double omega_max = 1000000;  // rad/sec
+  const double delta_end = 1000000;
+  const double delta_start = 0.0;
+
+  std::vector<std::complex<double>> steps = {0.0, time_ramp,
+                                             time_max - time_ramp, time_max};
+  cudaq::schedule schedule(steps, {"t"}, {});
+
+  // Basic Rydberg Hamiltonian
+  auto omega = cudaq::scalar_operator(
+      [time_ramp, time_max,
+       omega_max](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? omega_max : 0.0, 0.0);
+      });
+
+  auto phi = cudaq::scalar_operator(0.0);
+
+  auto delta = cudaq::scalar_operator(
+      [time_ramp, time_max, delta_start,
+       delta_end](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? delta_end : delta_start, 0.0);
+      });
+
+  auto hamiltonian =
+      cudaq::rydberg_hamiltonian(register_sites, omega, phi, delta);
+
+  // Evolve the system
+  auto result = cudaq::evolve(hamiltonian, schedule, 100);
+  result.get_sampling_result()->dump();
+
+  return 0;
+}
diff --git a/docs/sphinx/targets/cpp/quera_basic.cpp b/docs/sphinx/targets/cpp/quera_basic.cpp
new file mode 100644
index 00000000000..9d1202d4894
--- /dev/null
+++ b/docs/sphinx/targets/cpp/quera_basic.cpp
@@ -0,0 +1,82 @@
+// Compile and run with:
+// ```
+// nvq++ --target quera quera_basic.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials have been stored.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/schedule.h"
+#include <cmath>
+#include <map>
+#include <vector>
+
+// NOTE: QuEra Aquila system is available via Amazon Braket.
+// Credentials must be set before running this program.
+// Amazon Braket costs apply.
+
+// This example illustrates how to use QuEra's Aquila device on Braket with
+// CUDA-Q. It is a CUDA-Q implementation of the getting started materials for
+// Braket available here:
+// https://docs.aws.amazon.com/braket/latest/developerguide/braket-get-started-hello-ahs.html
+
+int main() {
+  // Topology initialization
+  const double a = 5.7e-6;
+  std::vector<std::pair<double, double>> register_sites;
+
+  auto make_coord = [a](double x, double y) {
+    return std::make_pair(x * a, y * a);
+  };
+
+  register_sites.push_back(make_coord(0.5, 0.5 + 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(0.5 + 1.0 / std::sqrt(2), 0.5));
+  register_sites.push_back(make_coord(0.5 + 1.0 / std::sqrt(2), -0.5));
+  register_sites.push_back(make_coord(0.5, -0.5 - 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(-0.5, -0.5 - 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(-0.5 - 1.0 / std::sqrt(2), -0.5));
+  register_sites.push_back(make_coord(-0.5 - 1.0 / std::sqrt(2), 0.5));
+  register_sites.push_back(make_coord(-0.5, 0.5 + 1.0 / std::sqrt(2)));
+
+  // Simulation Timing
+  const double time_max = 4e-6;   // seconds
+  const double time_ramp = 1e-7;  // seconds
+  const double omega_max = 6.3e6; // rad/sec
+  const double delta_start = -5 * omega_max;
+  const double delta_end = 5 * omega_max;
+
+  std::vector<std::complex<double>> steps = {0.0, time_ramp,
+                                             time_max - time_ramp, time_max};
+  cudaq::schedule schedule(steps, {"t"}, {});
+
+  // Basic Rydberg Hamiltonian
+  auto omega = cudaq::scalar_operator(
+      [time_ramp, time_max,
+       omega_max](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? omega_max : 0.0, 0.0);
+      });
+
+  auto phi = cudaq::scalar_operator(0.0);
+
+  auto delta = cudaq::scalar_operator(
+      [time_ramp, time_max, delta_start,
+       delta_end](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? delta_end : delta_start, 0.0);
+      });
+
+  auto hamiltonian =
+      cudaq::rydberg_hamiltonian(register_sites, omega, phi, delta);
+
+  // Evolve the system
+  auto result = cudaq::evolve_async(hamiltonian, schedule, 10).get();
+  result.get_sampling_result()->dump();
+
+  return 0;
+}
diff --git a/docs/sphinx/targets/cpp/quera_intro.cpp b/docs/sphinx/targets/cpp/quera_intro.cpp
new file mode 100644
index 00000000000..15d6bbfe86f
--- /dev/null
+++ b/docs/sphinx/targets/cpp/quera_intro.cpp
@@ -0,0 +1,85 @@
+// Compile and run with:
+// ```
+// nvq++ --target quera quera_intro.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials have been stored.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <cmath>
+#include <map>
+#include <vector>
+
+// This example illustrates how to use QuEra's Aquila device on Braket with
+// CUDA-Q. It is a CUDA-Q implementation of the getting started materials for
+// Braket available here:
+// https://github.com/amazon-braket/amazon-braket-examples/blob/main/examples/analog_hamiltonian_simulation/01_Introduction_to_Aquila.ipynb
+
+int main() {
+  // Topology initialization
+  const double separation = 5e-6;
+  const double block_separation = 15e-6;
+  const int k_max = 5;
+  const int m_max = 5;
+
+  std::vector<std::pair<double, double>> register_sites;
+
+  for (int k = 0; k < k_max; ++k) {
+    for (int m = 0; m < m_max; ++m) {
+      register_sites.push_back(
+          std::make_pair(block_separation * m,
+                         block_separation * k + separation / std::sqrt(3)));
+
+      register_sites.push_back(std::make_pair(
+          block_separation * m - separation / 2,
+          block_separation * k - separation / (2 * std::sqrt(3))));
+
+      register_sites.push_back(std::make_pair(
+          block_separation * m + separation / 2,
+          block_separation * k - separation / (2 * std::sqrt(3))));
+    }
+  }
+
+  // Simulation Timing
+  const double omega_const = 1.5e7;                     // rad/sec
+  const double time_ramp = 5e-8;                        // seconds
+  const double time_plateau = 7.091995761561453e-08;    // seconds
+  const double time_max = 2 * time_ramp + time_plateau; // seconds
+
+  std::vector<std::complex<double>> steps = {
+      0.0, time_ramp, time_ramp + time_plateau, time_max};
+  cudaq::schedule schedule(steps, {"t"}, {});
+
+  // Rydberg Hamiltonian with trapezoidal omega
+  auto omega = cudaq::scalar_operator(
+      [time_ramp, time_plateau, time_max,
+       omega_const](const std::unordered_map<std::string, std::complex<double>>
+                        &parameters) {
+        double t = std::real(parameters.at("t"));
+        double slope = omega_const / time_ramp;
+        double y_intercept = slope * time_max;
+
+        if (t > 0 && t < time_ramp + time_plateau) {
+          return std::complex<double>(slope * t, 0.0);
+        } else if (t > time_ramp && t < time_max) {
+          return std::complex<double>(omega_const, 0.0);
+        } else if (t > time_ramp + time_plateau && t < time_max) {
+          return std::complex<double>((-slope * t) + y_intercept, 0.0);
+        }
+        return std::complex<double>(0.0, 0.0);
+      });
+  auto phi = cudaq::scalar_operator(0.0);
+  auto delta = cudaq::scalar_operator(0.0);
+
+  auto hamiltonian =
+      cudaq::rydberg_hamiltonian(register_sites, omega, phi, delta);
+
+  // Evolve the system
+  auto result = cudaq::evolve(hamiltonian, schedule);
+  result.get_sampling_result()->dump();
+
+  return 0;
+}
diff --git a/python/cudaq/operator/dynamics.yml b/python/cudaq/operator/dynamics.yml
index 21c15bcd8ab..14ff2ccff5c 100644
--- a/python/cudaq/operator/dynamics.yml
+++ b/python/cudaq/operator/dynamics.yml
@@ -12,5 +12,5 @@ gpu-requirements: true
 config:
   nvqir-simulation-backend: dynamics
   platform-library: mqpu
-  preprocessor-defines: ["-D CUDAQ_DYNAMICS_TARGET"]
-  library-mode: true
\ No newline at end of file
+  preprocessor-defines: ["-D CUDAQ_ANALOG_TARGET"]
+  library-mode: true
diff --git a/runtime/cudaq/algorithms/evolve.h b/runtime/cudaq/algorithms/evolve.h
index 0d0f19f28db..edc315eca4d 100644
--- a/runtime/cudaq/algorithms/evolve.h
+++ b/runtime/cudaq/algorithms/evolve.h
@@ -83,7 +83,7 @@ evolve(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
        std::initializer_list<ObserveOpTy> observables = {},
        bool store_intermediate_results = false,
        std::optional<int> shots_count = std::nullopt) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   return cudaq::__internal__::evolveSingle(
       cudaq::__internal__::convertOp(hamiltonian), dimensions, schedule,
       initial_state, integrator,
@@ -113,7 +113,7 @@ evolve_result evolve(const HamTy &hamiltonian,
                      const std::vector<ObserveOpTy> &observables = {},
                      bool store_intermediate_results = false,
                      std::optional<int> shots_count = std::nullopt) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   return cudaq::__internal__::evolveSingle(
       cudaq::__internal__::convertOp(hamiltonian), dimensions, schedule,
       initial_state, integrator,
@@ -147,7 +147,7 @@ evolve(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
        std::initializer_list<ObserveOpTy> observables = {},
        bool store_intermediate_results = false,
        std::optional<int> shots_count = std::nullopt) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   std::vector<evolve_result> results;
   for (const auto &initial_state : initial_states)
     results.emplace_back(evolve(hamiltonian, dimensions, schedule,
@@ -183,13 +183,13 @@ evolve(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
        const std::vector<ObserveOpTy> &observables = {},
        bool store_intermediate_results = false,
        std::optional<int> shots_count = std::nullopt) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   std::vector<evolve_result> results;
   for (const auto &initial_state : initial_states)
-    results.emplace_back(evolve(hamiltonian, dimensions, schedule,
-                                initial_state, integrator, collapse_operators,
-                                observables, store_intermediate_results,
-                                shots_count));
+    results.emplace_back(evolve(
+        hamiltonian, dimensions, schedule, initial_states, integrator,
+        collapse_operators, initial_state, integrator, collapse_operators,
+        observables, store_intermediate_results, shots_count));
   return results;
 #else
   static_assert(
@@ -219,7 +219,7 @@ evolve_async(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
              std::initializer_list<ObserveOpTy> observables = {},
              bool store_intermediate_results = false,
              std::optional<int> shots_count = std::nullopt, int qpu_id = 0) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   // Clone the integrator to extend its lifetime.
   auto cloneIntegrator = integrator.clone();
   auto collapseOperators = cudaq::__internal__::convertOps(collapse_operators);
@@ -259,7 +259,7 @@ evolve_async(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
              const std::vector<ObserveOpTy> &observables = {},
              bool store_intermediate_results = false,
              std::optional<int> shots_count = std::nullopt, int qpu_id = 0) {
-#if defined(CUDAQ_DYNAMICS_TARGET)
+#if defined(CUDAQ_ANALOG_TARGET)
   // Clone the integrator to extend its lifetime.
   auto cloneIntegrator = integrator.clone();
   return __internal__::evolve_async(
@@ -277,4 +277,25 @@ evolve_async(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
              "recompile your application with '--target dynamics' flag.");
 #endif
 }
-} // namespace cudaq
\ No newline at end of file
+
+// Rydberg Hamiltonian
+evolve_result evolve(const cudaq::rydberg_hamiltonian &hamiltonian,
+                     const cudaq::schedule &schedule,
+                     std::optional<int> shots_count = std::nullopt) {
+  return cudaq::__internal__::evolveSingle(hamiltonian, schedule, shots_count);
+}
+
+async_evolve_result evolve_async(const cudaq::rydberg_hamiltonian &hamiltonian,
+                                 const cudaq::schedule &schedule,
+                                 std::optional<int> shots_count = std::nullopt,
+                                 int qpu_id = 0) {
+  return cudaq::__internal__::evolve_async(
+      [=]() {
+        ExecutionContext context("evolve");
+        cudaq::get_platform().set_exec_ctx(&context, qpu_id);
+        return evolve(hamiltonian, schedule, shots_count);
+      },
+      qpu_id);
+}
+
+} // namespace cudaq
diff --git a/runtime/cudaq/algorithms/evolve_internal.h b/runtime/cudaq/algorithms/evolve_internal.h
index 60303bf5f63..94ab3497b0d 100644
--- a/runtime/cudaq/algorithms/evolve_internal.h
+++ b/runtime/cudaq/algorithms/evolve_internal.h
@@ -164,5 +164,10 @@ evolve_result evolveSingle(
     const std::vector<operator_sum<cudaq::matrix_operator>> &observables = {},
     bool store_intermediate_results = false,
     std::optional<int> shots_count = std::nullopt);
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt);
+
 } // namespace __internal__
 } // namespace cudaq
diff --git a/runtime/cudaq/dynamics/CMakeLists.txt b/runtime/cudaq/dynamics/CMakeLists.txt
index 34e4903c6eb..968a87cb44a 100644
--- a/runtime/cudaq/dynamics/CMakeLists.txt
+++ b/runtime/cudaq/dynamics/CMakeLists.txt
@@ -12,13 +12,15 @@ set(INTERFACE_POSITION_INDEPENDENT_CODE ON)
 
 set(CUDAQ_OPS_SRC
   callback.cpp
-  scalar_operators.cpp 
+  scalar_operators.cpp
   spin_operators.cpp
   boson_operators.cpp
   fermion_operators.cpp
-  matrix_operators.cpp 
-  product_operators.cpp 
-  operator_sum.cpp 
+  matrix_operators.cpp
+  product_operators.cpp
+  operator_sum.cpp
+  rydberg_hamiltonian.cpp
+  evolution.cpp
   handler.cpp
   schedule.cpp
   helpers.cpp
@@ -28,8 +30,8 @@ add_library(${LIBRARY_NAME} SHARED ${CUDAQ_OPS_SRC})
 set_property(GLOBAL APPEND PROPERTY CUDAQ_RUNTIME_LIBS ${LIBRARY_NAME})
 target_compile_definitions(${LIBRARY_NAME} PRIVATE -DCUDAQ_INSTANTIATE_TEMPLATES)
 
-target_include_directories(${LIBRARY_NAME} 
-    PUBLIC 
+target_include_directories(${LIBRARY_NAME}
+    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/runtime>
        $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/eigen>
        $<INSTALL_INTERFACE:include>
diff --git a/runtime/cudaq/dynamics/evolution.cpp b/runtime/cudaq/dynamics/evolution.cpp
new file mode 100644
index 00000000000..636c9581746
--- /dev/null
+++ b/runtime/cudaq/dynamics/evolution.cpp
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq::__internal__ {
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt) {
+  auto amp = hamiltonian.get_amplitude();
+  auto ph = hamiltonian.get_phase();
+  auto dg = hamiltonian.get_delta_global();
+  std::vector<std::pair<double, double>> amp_ts;
+  std::vector<std::pair<double, double>> ph_ts;
+  std::vector<std::pair<double, double>> dg_ts;
+  for (const auto &step : schedule) {
+    auto amp_res = amp.evaluate({{"t", step}});
+    amp_ts.push_back(std::make_pair(amp_res.real(), step.real()));
+
+    auto ph_res = ph.evaluate({{"t", step}});
+    ph_ts.push_back(std::make_pair(ph_res.real(), step.real()));
+
+    auto dg_res = dg.evaluate({{"t", step}});
+    dg_ts.push_back(std::make_pair(dg_res.real(), step.real()));
+  }
+
+  auto atoms = cudaq::ahs::AtomArrangement();
+  for (auto pair : hamiltonian.get_atom_sites())
+    atoms.sites.push_back({pair.first, pair.second});
+  atoms.filling = hamiltonian.get_atom_filling();
+
+  auto omega = cudaq::ahs::PhysicalField();
+  omega.time_series = cudaq::ahs::TimeSeries(amp_ts);
+
+  auto phi = cudaq::ahs::PhysicalField();
+  phi.time_series = cudaq::ahs::TimeSeries(ph_ts);
+
+  auto delta = cudaq::ahs::PhysicalField();
+  delta.time_series = cudaq::ahs::TimeSeries(dg_ts);
+
+  auto drive = cudaq::ahs::DrivingField();
+  drive.amplitude = omega;
+  drive.phase = phi;
+  drive.detuning = delta;
+
+  auto program = cudaq::ahs::Program();
+  program.setup.ahs_register = atoms;
+  program.hamiltonian.drivingFields = {drive};
+  program.hamiltonian.localDetuning = {};
+
+  std::ostringstream programName;
+  programName << "__analog_hamiltonian_kernel__" << []() {
+    const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    const auto length = sizeof(chars) / sizeof(char);
+    std::random_device rd;
+    std::mt19937 generator(rd());
+    std::uniform_int_distribution<> distribution(0, length - 1);
+    std::string result;
+    result.reserve(10);
+    for (int i = 0; i < 10; ++i)
+      result += chars[distribution(generator)];
+    return result;
+  }();
+
+  auto programJson = nlohmann::json(program);
+
+  auto &platform = cudaq::get_platform();
+  auto ctx =
+      std::make_unique<ExecutionContext>("sample", shots_count.value_or(100));
+  ctx->asyncExec = false;
+  platform.set_exec_ctx(ctx.get());
+
+  auto programString = programJson.dump();
+  cudaq::debug("Program JSON: {}", programString);
+
+  auto dynamicResult = cudaq::altLaunchKernel(
+      programName.str().c_str(), KernelThunkType(nullptr),
+      (void *)(const_cast<char *>(programString.c_str())), 0, 0);
+
+  auto sampleResults = ctx->result;
+  platform.reset_exec_ctx();
+
+  return evolve_result(sampleResults);
+}
+
+} // namespace cudaq::__internal__
diff --git a/runtime/cudaq/dynamics/rydberg_hamiltonian.cpp b/runtime/cudaq/dynamics/rydberg_hamiltonian.cpp
new file mode 100644
index 00000000000..d207bc07406
--- /dev/null
+++ b/runtime/cudaq/dynamics/rydberg_hamiltonian.cpp
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <sstream>
+#include <stdexcept>
+
+namespace cudaq {
+rydberg_hamiltonian::rydberg_hamiltonian(
+    const std::vector<coordinate> &atom_sites, const scalar_operator &amplitude,
+    const scalar_operator &phase, const scalar_operator &delta_global,
+    const std::vector<int> &atom_filling,
+    const std::optional<std::pair<scalar_operator, std::vector<double>>>
+        &delta_local)
+    : atom_sites(atom_sites), amplitude(amplitude), phase(phase),
+      delta_global(delta_global), delta_local(delta_local) {
+  if (atom_filling.empty()) {
+    this->atom_filling = std::vector<int>(atom_sites.size(), 1);
+  } else if (atom_sites.size() != atom_filling.size()) {
+    throw std::invalid_argument(
+        "Size of `atom_sites` and `atom_filling` must be equal.");
+  } else {
+    this->atom_filling = atom_filling;
+  }
+
+  if (delta_local.has_value()) {
+    throw std::runtime_error(
+        "Local detuning is an experimental feature not yet supported.");
+  }
+}
+
+const std::vector<rydberg_hamiltonian::coordinate> &
+rydberg_hamiltonian::get_atom_sites() const {
+  return atom_sites;
+}
+
+const std::vector<int> &rydberg_hamiltonian::get_atom_filling() const {
+  return atom_filling;
+}
+
+const scalar_operator &rydberg_hamiltonian::get_amplitude() const {
+  return amplitude;
+}
+
+const scalar_operator &rydberg_hamiltonian::get_phase() const { return phase; }
+
+const scalar_operator &rydberg_hamiltonian::get_delta_global() const {
+  return delta_global;
+}
+} // namespace cudaq
diff --git a/runtime/cudaq/operators.h b/runtime/cudaq/operators.h
index ba7c1d94a25..e45247edb35 100644
--- a/runtime/cudaq/operators.h
+++ b/runtime/cudaq/operators.h
@@ -589,6 +589,52 @@ class product_operator {
   friend product_operator<T> operator_handler::identity(int target);
 };
 
+/// @brief Representation of a time-dependent Hamiltonian for Rydberg system
+class rydberg_hamiltonian {
+public:
+  using coordinate = std::pair<double, double>;
+
+  /// @brief Constructor.
+  /// @param atom_sites List of 2D coordinates for trap sites.
+  /// @param amplitude Time-dependent driving amplitude, Omega(t).
+  /// @param phase Time-dependent driving phase, phi(t).
+  /// @param delta_global Time-dependent driving detuning, Delta_global(t).
+  /// @param atom_filling Optional. Marks occupied trap sites (1) and empty
+  /// sites (0). Defaults to all sites occupied.
+  /// @param delta_local Optional. A tuple of Delta_local(t) and site dependent
+  /// local detuning factors.
+  rydberg_hamiltonian(
+      const std::vector<coordinate> &atom_sites,
+      const scalar_operator &amplitude, const scalar_operator &phase,
+      const scalar_operator &delta_global,
+      const std::vector<int> &atom_filling = {},
+      const std::optional<std::pair<scalar_operator, std::vector<double>>>
+          &delta_local = std::nullopt);
+
+  /// @brief Get atom sites.
+  const std::vector<coordinate> &get_atom_sites() const;
+
+  /// @brief Get atom filling.
+  const std::vector<int> &get_atom_filling() const;
+
+  /// @brief Get amplitude operator.
+  const scalar_operator &get_amplitude() const;
+
+  /// @brief Get phase operator.
+  const scalar_operator &get_phase() const;
+
+  /// @brief Get global detuning operator.
+  const scalar_operator &get_delta_global() const;
+
+private:
+  std::vector<coordinate> atom_sites;
+  std::vector<int> atom_filling;
+  scalar_operator amplitude;
+  scalar_operator phase;
+  scalar_operator delta_global;
+  std::optional<std::pair<scalar_operator, std::vector<double>>> delta_local;
+};
+
 // type aliases for convenience
 typedef std::unordered_map<std::string, std::complex<double>> parameter_map;
 typedef std::unordered_map<int, int> dimension_map;
diff --git a/runtime/cudaq/platform/pasqal/pasqal.yml b/runtime/cudaq/platform/pasqal/pasqal.yml
index 7d787ee9098..23419e9c2b6 100644
--- a/runtime/cudaq/platform/pasqal/pasqal.yml
+++ b/runtime/cudaq/platform/pasqal/pasqal.yml
@@ -13,6 +13,8 @@ config:
   platform-qpu: pasqal
   # Add the pasqal-qpu library to the link list
   link-libs: ["-lcudaq-pasqal-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
diff --git a/runtime/cudaq/platform/quera/quera.yml b/runtime/cudaq/platform/quera/quera.yml
index 78feaddbbcd..8e60dc18c2f 100644
--- a/runtime/cudaq/platform/quera/quera.yml
+++ b/runtime/cudaq/platform/quera/quera.yml
@@ -15,6 +15,8 @@ config:
   gen-target-backend: true
   # Add the quera-qpu library to the link list
   link-libs: ["-lcudaq-quera-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
 
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index fc6802b9522..ec0784adaa9 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -13,7 +13,7 @@ set (CMAKE_CXX_FLAGS
 SET(CMAKE_EXE_LINKER_FLAGS "")
 SET(CMAKE_SHARED_LINKER_FLAGS "")
 
-set(CUDAQ_RUNTIME_TEST_SOURCES 
+set(CUDAQ_RUNTIME_TEST_SOURCES
   # Integration tests
   integration/adjoint_tester.cpp
   integration/builder_tester.cpp
@@ -49,9 +49,9 @@ set(CUDAQ_RUNTIME_TEST_SOURCES
 # Make it so we can get function symbols
 set (CMAKE_ENABLE_EXPORTS TRUE)
 
-## This Macro allows us to create a test_runtime executable for 
+## This Macro allows us to create a test_runtime executable for
 ## the sources in CUDAQ_RUNTIME_TEST_SOURCE for a specific backend simulator
-macro (create_tests_with_backend NVQIR_BACKEND EXTRA_BACKEND_TESTER) 
+macro (create_tests_with_backend NVQIR_BACKEND EXTRA_BACKEND_TESTER)
   set(TEST_EXE_NAME "test_runtime_${NVQIR_BACKEND}")
   string(REPLACE "-" "_" NVQIR_BACKEND_OUT ${NVQIR_BACKEND})
   add_executable(${TEST_EXE_NAME} main.cpp ${CUDAQ_RUNTIME_TEST_SOURCES} ${EXTRA_BACKEND_TESTER})
@@ -60,15 +60,15 @@ macro (create_tests_with_backend NVQIR_BACKEND EXTRA_BACKEND_TESTER)
   target_include_directories(${TEST_EXE_NAME} PRIVATE .)
 
   # On GCC, the default is --as-needed for linking, and therefore the
-  # nvqir-simulation plugin may not get picked up. This works as is on clang 
-  # But here we add it purposefully to avoid that bug. 
+  # nvqir-simulation plugin may not get picked up. This works as is on clang
+  # But here we add it purposefully to avoid that bug.
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(${TEST_EXE_NAME} PRIVATE -Wl,--no-as-needed)
   endif()
   target_link_libraries(${TEST_EXE_NAME}
-    PUBLIC 
+    PUBLIC
     nvqir-${NVQIR_BACKEND}
-    nvqir  
+    nvqir
     cudaq
     fmt::fmt-header-only
     cudaq-platform-default
@@ -109,20 +109,20 @@ create_tests_with_backend(qpp backends/QPPTester.cpp)
 create_tests_with_backend(dm backends/QPPDMTester.cpp)
 create_tests_with_backend(stim "")
 
-if (CUSTATEVEC_ROOT AND CUDA_FOUND) 
+if (CUSTATEVEC_ROOT AND CUDA_FOUND)
   create_tests_with_backend(custatevec-fp32 "")
   # Given that the fp32 and fp64 difference is largely inherited
-  # from a dependency, we omit fp64 tests here and rely on the 
+  # from a dependency, we omit fp64 tests here and rely on the
   # dependency to to validate that functionality.
   # create_tests_with_backend(custatevec-fp64 "")
-  
+
   add_executable(test_mqpu main.cpp mqpu/mqpu_tester.cpp)
   # Need to force the link to nvqir-qpp here if gcc.
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(test_mqpu PRIVATE -Wl,--no-as-needed)
   endif()
   target_link_libraries(test_mqpu
-    PRIVATE 
+    PRIVATE
     cudaq
     cudaq-builder
     cudaq-platform-mqpu
@@ -132,20 +132,20 @@ if (CUSTATEVEC_ROOT AND CUDA_FOUND)
 
   # Test CUDAQ_OBSERVE_FROM_SAMPLING=ON mode.
   # (term-by-term expectation value calculation by applying change-of-basis gates then reverting them)
-  add_executable(test_custatevec_observe_from_sampling 
-    integration/builder_tester.cpp  
+  add_executable(test_custatevec_observe_from_sampling
+    integration/builder_tester.cpp
     integration/deuteron_variational_tester.cpp
     integration/gradient_tester.cpp
     integration/nlopt_tester.cpp
   )
   target_include_directories(test_custatevec_observe_from_sampling PRIVATE .)
-  target_compile_definitions(test_custatevec_observe_from_sampling 
+  target_compile_definitions(test_custatevec_observe_from_sampling
                              PRIVATE -DNVQIR_BACKEND_NAME=custatevec_fp32)
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(test_custatevec_observe_from_sampling PRIVATE -Wl,--no-as-needed)
   endif()
   target_link_libraries(test_custatevec_observe_from_sampling
-    PRIVATE 
+    PRIVATE
     cudaq
     cudaq-builder
     cudaq-platform-default
@@ -166,7 +166,7 @@ if (CUSTATEVEC_ROOT AND CUDA_FOUND)
           target_link_options(test_mpi PRIVATE -Wl,--no-as-needed)
         endif()
         target_link_libraries(test_mpi
-            PRIVATE 
+            PRIVATE
             cudaq
             cudaq-platform-mqpu
             nvqir-custatevec-fp32
@@ -176,7 +176,7 @@ if (CUSTATEVEC_ROOT AND CUDA_FOUND)
         add_test(NAME MPITest COMMAND ${MPIEXEC} --allow-run-as-root -np 2 bash ${CMAKE_BINARY_DIR}/unittests/run_mpi.sh)
         set_tests_properties(MPITest PROPERTIES LABELS "gpu_required;mgpus_required")
       endif()
-    endif() 
+    endif()
 
     add_executable(test_gpu_get_state main.cpp gpu/get_state_tester.cu)
     # Need to force the link to nvqir-qpp here if gcc.
@@ -186,14 +186,14 @@ if (CUSTATEVEC_ROOT AND CUDA_FOUND)
     target_compile_options(test_gpu_get_state PRIVATE -Wno-suggest-override -Wno-attributes)
     target_include_directories(test_gpu_get_state PRIVATE .)
     target_link_libraries(test_gpu_get_state
-      PRIVATE 
+      PRIVATE
       cudaq
       cudaq-builder
       cudaq-platform-mqpu
       nvqir-custatevec-fp64
       gtest_main)
       gtest_discover_tests(test_gpu_get_state PROPERTIES LABELS "gpu_required")
-  endif() 
+  endif()
 endif()
 
 if(TARGET nvqir-tensornet)
@@ -213,7 +213,7 @@ if(TARGET nvqir-tensornet)
           target_link_options(test_tensornet_mpi PRIVATE -Wl,--no-as-needed)
         endif()
         target_link_libraries(test_tensornet_mpi
-            PRIVATE 
+            PRIVATE
             cudaq
             cudaq-platform-default
             nvqir-tensornet
@@ -223,22 +223,22 @@ if(TARGET nvqir-tensornet)
       endif() # NGPUS
     endif() # NVIDIA_SMI
   endif() # MPI_CXX_FOUND
-  
+
   # Test CUDAQ_TENSORNET_OBSERVE_CONTRACT_PATH_REUSE=ON mode (on a few test cases that have cudaq::observe)
-  add_executable(test_tensornet_observe_path_reuse 
-    integration/builder_tester.cpp  
+  add_executable(test_tensornet_observe_path_reuse
+    integration/builder_tester.cpp
     integration/deuteron_variational_tester.cpp
     integration/observe_result_tester.cpp
     integration/noise_tester.cpp # This test contains noisy observe test cases.
   )
   target_include_directories(test_tensornet_observe_path_reuse PRIVATE .)
-  target_compile_definitions(test_tensornet_observe_path_reuse 
+  target_compile_definitions(test_tensornet_observe_path_reuse
                              PRIVATE -DNVQIR_BACKEND_NAME=tensornet)
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(test_tensornet_observe_path_reuse PRIVATE -Wl,--no-as-needed)
   endif()
   target_link_libraries(test_tensornet_observe_path_reuse
-    PRIVATE 
+    PRIVATE
     cudaq
     cudaq-builder
     cudaq-platform-default
@@ -246,22 +246,22 @@ if(TARGET nvqir-tensornet)
     gtest_main)
   # Run this test with "CUDAQ_TENSORNET_OBSERVE_CONTRACT_PATH_REUSE=TRUE"
   gtest_discover_tests(test_tensornet_observe_path_reuse TEST_SUFFIX _PathReuse PROPERTIES ENVIRONMENT "CUDAQ_TENSORNET_OBSERVE_CONTRACT_PATH_REUSE=ON" PROPERTIES LABELS "gpu_required")
-endif() 
+endif()
 
 # Create an executable for SpinOp UnitTests
-set(CUDAQ_SPIN_TEST_SOURCES 
+set(CUDAQ_SPIN_TEST_SOURCES
    # Spin
    spin_op/SpinOpTester.cpp
 )
 add_executable(test_spin main.cpp ${CUDAQ_SPIN_TEST_SOURCES})
 target_link_libraries(test_spin
-  PRIVATE 
+  PRIVATE
   cudaq-spin
   gtest_main)
 gtest_discover_tests(test_spin)
 
 # Create an executable for operators UnitTests
-set(CUDAQ_OPERATOR_TEST_SOURCES 
+set(CUDAQ_OPERATOR_TEST_SOURCES
    dynamics/utils.cpp
    dynamics/scalar_operator.cpp
    dynamics/matrix_operator.cpp
@@ -271,6 +271,7 @@ set(CUDAQ_OPERATOR_TEST_SOURCES
    dynamics/operator_conversions.cpp
    dynamics/product_operator.cpp
    dynamics/operator_sum.cpp
+   dynamics/rydberg_hamiltonian.cpp
 )
 add_executable(test_operators main.cpp ${CUDAQ_OPERATOR_TEST_SOURCES})
 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
@@ -295,9 +296,9 @@ if (CUDA_FOUND)
         ${CUTENSOR_ROOT}/lib64/${CUDAToolkit_VERSION_MAJOR}
         ${CUTENSOR_ROOT}/lib/${CUDAToolkit_VERSION_MAJOR}
   )
-  
+
   # Create an executable for dynamics UnitTests
-  set(CUDAQ_DYNAMICS_TEST_SOURCES 
+  set(CUDAQ_DYNAMICS_TEST_SOURCES
     dynamics/test_RungeKuttaIntegrator.cpp
     dynamics/test_Helpers.cpp
     dynamics/test_CuDensityMatState.cpp
@@ -307,7 +308,7 @@ if (CUDA_FOUND)
     dynamics/test_EvolveApi.cpp
   )
   add_executable(test_dynamics main.cpp ${CUDAQ_DYNAMICS_TEST_SOURCES})
-  target_compile_definitions(test_dynamics PRIVATE -DCUDAQ_DYNAMICS_TARGET)
+  target_compile_definitions(test_dynamics PRIVATE -DCUDAQ_ANALOG_TARGET)
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(test_dynamics PRIVATE -Wl,--no-as-needed)
   endif()
@@ -331,7 +332,7 @@ if (CUDA_FOUND)
   if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
     target_link_options(test_evolve_async PRIVATE -Wl,--no-as-needed)
   endif()
-  target_compile_definitions(test_evolve_async PRIVATE -DCUDAQ_DYNAMICS_TARGET)
+  target_compile_definitions(test_evolve_async PRIVATE -DCUDAQ_ANALOG_TARGET)
   target_link_libraries(test_evolve_async
     PRIVATE
     cudaq-spin
@@ -353,7 +354,7 @@ if (CUDA_FOUND)
     if (${NGPUS} GREATER_EQUAL 2)
       gtest_discover_tests(test_evolve_async PROPERTIES LABELS "gpu_required;mgpus_required")
     endif()
-  endif() 
+  endif()
 endif()
 
 add_subdirectory(plugin)
@@ -365,7 +366,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
   target_link_options(test_qudit PRIVATE -Wl,--no-as-needed)
 endif()
 target_link_libraries(test_qudit
-  PRIVATE 
+  PRIVATE
   cudaq
   cudaq-platform-default
   cudaq-em-qudit
@@ -378,7 +379,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
   target_link_options(test_photonics PRIVATE -Wl,--no-as-needed)
 endif()
 target_link_libraries(test_photonics
-  PRIVATE 
+  PRIVATE
   cudaq
   cudaq-platform-default
   cudaq-em-photonics
@@ -391,7 +392,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
   target_link_options(test_utils PRIVATE -Wl,--no-as-needed)
 endif()
 target_link_libraries(test_utils
-  PRIVATE 
+  PRIVATE
   cudaq
   cudaq-platform-default
   cudaq-em-photonics
@@ -403,14 +404,14 @@ gtest_discover_tests(test_utils)
 # Create an executable for MPI UnitTests
 # (only if MPI was found, i.e., the builtin plugin is available)
 if (MPI_CXX_FOUND)
-  set(CUDAQ_MPI_TEST_SOURCES 
+  set(CUDAQ_MPI_TEST_SOURCES
     mpi/mpi_tester.cpp
   )
   add_executable(test_mpi_plugin ${CUDAQ_MPI_TEST_SOURCES})
   set(NUM_PROCS 4)
   target_compile_definitions(test_mpi_plugin PRIVATE -DNUM_PROCS=${NUM_PROCS})
   target_link_libraries(test_mpi_plugin
-    PRIVATE 
+    PRIVATE
     cudaq
     cudaq-platform-default
     nvqir-qpp
@@ -423,7 +424,7 @@ if (MPI_CXX_FOUND)
   if ("${CHECK_ALLOW_RUN_AS_ROOT_RESULTS}" STREQUAL "")
     set(MPI_EXEC_CMD_ARGS "--allow-run-as-root")
   endif()
-  
+
   add_test(NAME MPIApiTest COMMAND ${MPIEXEC} ${MPI_EXEC_CMD_ARGS} -np ${NUM_PROCS} ${CMAKE_BINARY_DIR}/unittests/test_mpi_plugin)
 endif()
 
@@ -453,7 +454,7 @@ if (CUDAQ_ENABLE_PYTHON)
   target_include_directories(test_domains PRIVATE .)
   set_property(TARGET test_domains PROPERTY ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python")
   target_link_libraries(test_domains
-    PRIVATE 
+    PRIVATE
     cudaq
     cudaq-platform-default
     nvqir nvqir-qpp
@@ -464,4 +465,3 @@ if (CUDAQ_ENABLE_PYTHON)
   gtest_discover_tests(test_domains
     TEST_SUFFIX _Sampling PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python")
 endif()
-
diff --git a/unittests/dynamics/rydberg_hamiltonian.cpp b/unittests/dynamics/rydberg_hamiltonian.cpp
new file mode 100644
index 00000000000..47ba58dc694
--- /dev/null
+++ b/unittests/dynamics/rydberg_hamiltonian.cpp
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * 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. *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <gtest/gtest.h>
+
+using namespace cudaq;
+
+TEST(RydbergHamiltonianTest, ConstructorValidInputs) {
+  // Valid atom sites
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, ConstructorWithAtomFilling) {
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  std::vector<int> atom_filling = {1, 0, 1};
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                  atom_filling);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling(), atom_filling);
+}
+
+TEST(RydbergHamiltonianTest, InvalidAtomFillingSize) {
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid atom filling size
+  std::vector<int> atom_filling = {1, 0};
+
+  EXPECT_ANY_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase,
+                                       delta_global, atom_filling));
+}
+
+TEST(RydbergHamiltonianTest, UnsupportedLocalDetuning) {
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid delta_local
+  auto delta_local =
+      std::make_pair(scalar_operator(0.5), std::vector<double>{0.1, 0.2, 0.3});
+
+  EXPECT_ANY_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase,
+                                       delta_global, {}, delta_local));
+}
+
+TEST(RydbergHamiltonianTest, Accessors) {
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites(), atom_sites);
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, DefaultAtomFilling) {
+  std::vector<rydberg_hamiltonian::coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  std::vector<int> expected_filling(atom_sites.size(), 1);
+  EXPECT_EQ(hamiltonian.get_atom_filling(), expected_filling);
+}


Reviews:
user: login: schweitzpgi
body: Thanks, Dobri. LGTM with a quick skim. Just a couple of nits.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T20:47:43Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:16:56Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:18:17Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:22:08Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:24:50Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:31:28Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:40:15Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:41:58Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:43:24Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T21:43:52Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T22:22:45Z
user: login: nvidia-dobri
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T04:00:21Z
user: login: nvidia-dobri
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T04:10:48Z
user: login: nvidia-dobri
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T04:10:58Z
user: login: nvidia-dobri
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T04:13:22Z
user: login: nvidia-dobri
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T04:14:32Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T06:11:06Z
user: login: khalatepradnya
body: LGTM. Thanks, @nvidia-dobri .
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-07T06:18:28Z
user: login: sacpis
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-07T20:03:30Z
user: login: bmhowe23
body: I just reviewed the changes in the .github directory ... they LGTM.
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-07T20:28:35Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T22:25:49Z
user: login: khalatepradnya
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T23:31:28Z

Review comments:
diff_hunk: @@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq {
+namespace __internal__ {
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt) {
+  auto amp = hamiltonian.get_amplitude();
+  auto ph = hamiltonian.get_phase();
+  auto dg = hamiltonian.get_delta_global();
+  std::vector<std::pair<double, double>> amp_ts;
+  std::vector<std::pair<double, double>> ph_ts;
+  std::vector<std::pair<double, double>> dg_ts;
+  for (const auto &step : schedule) {
+    auto amp_res = amp.evaluate({{"t", step}});
+    amp_ts.push_back(std::make_pair(amp_res.real(), step.real()));
+
+    auto ph_res = ph.evaluate({{"t", step}});
+    ph_ts.push_back(std::make_pair(ph_res.real(), step.real()));
+
+    auto dg_res = dg.evaluate({{"t", step}});
+    dg_ts.push_back(std::make_pair(dg_res.real(), step.real()));
+  }
+
+  auto atoms = cudaq::ahs::AtomArrangement();
+  for (auto pair : hamiltonian.get_atom_sites()) {
path: runtime/cudaq/dynamics/evolution.cpp
user: login: schweitzpgi
body: nit: braces not needed
created_at: 2025-03-06T20:43:42Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq {
+namespace __internal__ {
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt) {
+  auto amp = hamiltonian.get_amplitude();
+  auto ph = hamiltonian.get_phase();
+  auto dg = hamiltonian.get_delta_global();
+  std::vector<std::pair<double, double>> amp_ts;
+  std::vector<std::pair<double, double>> ph_ts;
+  std::vector<std::pair<double, double>> dg_ts;
+  for (const auto &step : schedule) {
+    auto amp_res = amp.evaluate({{"t", step}});
+    amp_ts.push_back(std::make_pair(amp_res.real(), step.real()));
+
+    auto ph_res = ph.evaluate({{"t", step}});
+    ph_ts.push_back(std::make_pair(ph_res.real(), step.real()));
+
+    auto dg_res = dg.evaluate({{"t", step}});
+    dg_ts.push_back(std::make_pair(dg_res.real(), step.real()));
+  }
+
+  auto atoms = cudaq::ahs::AtomArrangement();
+  for (auto pair : hamiltonian.get_atom_sites()) {
+    atoms.sites.push_back({pair.first, pair.second});
+  }
+  atoms.filling = hamiltonian.get_atom_filling();
+
+  auto omega = cudaq::ahs::PhysicalField();
+  omega.time_series = cudaq::ahs::TimeSeries(amp_ts);
+
+  auto phi = cudaq::ahs::PhysicalField();
+  phi.time_series = cudaq::ahs::TimeSeries(ph_ts);
+
+  auto delta = cudaq::ahs::PhysicalField();
+  delta.time_series = cudaq::ahs::TimeSeries(dg_ts);
+
+  auto drive = cudaq::ahs::DrivingField();
+  drive.amplitude = omega;
+  drive.phase = phi;
+  drive.detuning = delta;
+
+  auto program = cudaq::ahs::Program();
+  program.setup.ahs_register = atoms;
+  program.hamiltonian.drivingFields = {drive};
+  program.hamiltonian.localDetuning = {};
+
+  std::ostringstream programName;
+  programName << "__analog_hamiltonian_kernel__" << []() {
+    const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
path: runtime/cudaq/dynamics/evolution.cpp
user: login: schweitzpgi
body: Do you really need to create a string object? Or can this be
```c++
  constexpr const char chars[] = "....";
```
created_at: 2025-03-06T20:45:21Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq {
+namespace __internal__ {
path: runtime/cudaq/dynamics/evolution.cpp
user: login: schweitzpgi
body: ```suggestion
namespace cudaq::__internal__ {
```
No need to use Bronze Age C++. :) 
created_at: 2025-03-06T20:46:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+// Compile and run with:
+// ```
+// nvq++ --target pasqal pasqal.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials (PASQAL_AUTH_TOKEN, PASQAL_PROJECT_ID)
+// have been set.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
path: docs/sphinx/targets/cpp/pasqal.cpp
user: login: khalatepradnya
body: Q: Do we need to include all of these individually?
Wouldn't `#include <cudaq.h>` suffice?
created_at: 2025-03-06T21:16:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+// Compile and run with:
+// ```
+// nvq++ --target pasqal pasqal.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials (PASQAL_AUTH_TOKEN, PASQAL_PROJECT_ID)
+// have been set.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
path: docs/sphinx/targets/cpp/pasqal.cpp
user: login: khalatepradnya
body: In other words, shouldn't users get `evolve` by default? (like `sample` and `observe`)
created_at: 2025-03-06T21:18:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+// Compile and run with:
+// ```
+// nvq++ --target pasqal pasqal.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials (PASQAL_AUTH_TOKEN, PASQAL_PROJECT_ID)
+// have been set.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <cmath>
+#include <map>
+#include <vector>
+
+// This example illustrates how to use Pasqal's EMU_MPS emulator over Pasqal's
+// cloud via CUDA-Q. Contact Pasqal at help@pasqal.com or through
+// https://community.pasqal.com for assistance.
+
+int main() {
+  // Topology initialization
+  const double a = 5e-6;
+  std::vector<std::pair<double, double>> register_sites;
+  register_sites.push_back(std::make_pair(a, 0.0));
+  register_sites.push_back(std::make_pair(2 * a, 0.0));
+  register_sites.push_back(std::make_pair(3 * a, 0.0));
+
+  // Simulation Timing
+  const double time_ramp = 0.000001; // seconds
+  const double time_max = 0.000003;  // seconds
+  const double omega_max = 1000000;  // rad/sec
+  const double delta_end = 1000000;
+  const double delta_start = 0.0;
+
+  std::vector<std::complex<double>> steps = {0.0, time_ramp,
+                                             time_max - time_ramp, time_max};
+  cudaq::schedule schedule(steps, {"t"}, {});
+
+  // Basic Rydberg Hamiltonian
+  auto omega = cudaq::scalar_operator(
+      [time_ramp, time_max,
+       omega_max](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? omega_max : 0.0, 0.0);
+      });
+
+  auto phi = cudaq::scalar_operator(0.0);
+
+  auto delta = cudaq::scalar_operator(
+      [time_ramp, time_max, delta_start,
+       delta_end](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? delta_end : delta_start, 0.0);
+      });
+
+  auto hamiltonian =
+      cudaq::rydberg_hamiltonian(register_sites, omega, phi, delta);
+
+  // Evolve the system
+  auto result = cudaq::evolve(hamiltonian, schedule, 100);
+  result.get_sampling_result()->dump();
+
+  return 0;
+}
path: docs/sphinx/targets/cpp/pasqal.cpp
user: login: khalatepradnya
body: This example can be added to the nightly integration test suite for Pasqal - [here](https://github.com/NVIDIA/cuda-quantum/blob/main/.github/workflows/integration_tests.yml#L708).
(See how it is done for Infleqtion - one C++ test and one Python test so that both frontends are covered.)
This change can go as a follow-up.
created_at: 2025-03-06T21:22:08Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,83 @@
+// Compile and run with:
+// ```
+// nvq++ --target quera quera_basic.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials have been stored.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <cmath>
+#include <map>
+#include <vector>
+
+// NOTE: QuEra Aquila system is available via Amazon Braket.
+// Credentials must be set before running this program.
+// Amazon Braket costs apply.
+
+// This example illustrates how to use QuEra's Aquila device on Braket with
+// CUDA-Q. It is a CUDA-Q implementation of the getting started materials for
+// Braket available here:
+// https://docs.aws.amazon.com/braket/latest/developerguide/braket-get-started-hello-ahs.html
+
+int main() {
+  // Topology initialization
+  const double a = 5.7e-6;
+  std::vector<std::pair<double, double>> register_sites;
+
+  auto make_coord = [a](double x, double y) {
+    return std::make_pair(x * a, y * a);
+  };
+
+  register_sites.push_back(make_coord(0.5, 0.5 + 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(0.5 + 1.0 / std::sqrt(2), 0.5));
+  register_sites.push_back(make_coord(0.5 + 1.0 / std::sqrt(2), -0.5));
+  register_sites.push_back(make_coord(0.5, -0.5 - 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(-0.5, -0.5 - 1.0 / std::sqrt(2)));
+  register_sites.push_back(make_coord(-0.5 - 1.0 / std::sqrt(2), -0.5));
+  register_sites.push_back(make_coord(-0.5 - 1.0 / std::sqrt(2), 0.5));
+  register_sites.push_back(make_coord(-0.5, 0.5 + 1.0 / std::sqrt(2)));
+
+  // Simulation Timing
+  const double time_max = 4e-6;   // seconds
+  const double time_ramp = 1e-7;  // seconds
+  const double omega_max = 6.3e6; // rad/sec
+  const double delta_start = -5 * omega_max;
+  const double delta_end = 5 * omega_max;
+
+  std::vector<std::complex<double>> steps = {0.0, time_ramp,
+                                             time_max - time_ramp, time_max};
+  cudaq::schedule schedule(steps, {"t"}, {});
+
+  // Basic Rydberg Hamiltonian
+  auto omega = cudaq::scalar_operator(
+      [time_ramp, time_max,
+       omega_max](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? omega_max : 0.0, 0.0);
+      });
+
+  auto phi = cudaq::scalar_operator(0.0);
+
+  auto delta = cudaq::scalar_operator(
+      [time_ramp, time_max, delta_start,
+       delta_end](const std::unordered_map<std::string, std::complex<double>>
+                      &parameters) {
+        double t = std::real(parameters.at("t"));
+        return std::complex<double>(
+            (t > time_ramp && t < time_max) ? delta_end : delta_start, 0.0);
+      });
+
+  auto hamiltonian =
+      cudaq::rydberg_hamiltonian(register_sites, omega, phi, delta);
+
+  // Evolve the system
+  auto result = cudaq::evolve(hamiltonian, schedule, 10);
path: docs/sphinx/targets/cpp/quera_basic.cpp
user: login: khalatepradnya
body: Can you update one of these examples to use `evolve_async` API?
created_at: 2025-03-06T21:24:50Z
author_association: COLLABORATOR
diff_hunk: @@ -277,4 +277,25 @@ evolve_async(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
              "recompile your application with '--target dynamics' flag.");
 #endif
 }
-} // namespace cudaq
\ No newline at end of file
+
+// Rydberg Hamiltonian
+evolve_result evolve(const cudaq::rydberg_hamiltonian &hamiltonian,
+                     const cudaq::schedule &schedule,
+                     std::optional<int> shots_count = std::nullopt) {
+  return cudaq::__internal__::evolveSingle(hamiltonian, schedule, shots_count);
+}
+
+async_evolve_result async_evolve(const cudaq::rydberg_hamiltonian &hamiltonian,
+                                 const cudaq::schedule &schedule,
+                                 std::optional<int> shots_count = std::nullopt,
+                                 int qpu_id = 0) {
+  return cudaq::__internal__::evolve_async(
+      [=]() {
+        ExecutionContext context("evolve");
+        cudaq::get_platform().set_exec_ctx(&context, qpu_id);
+        return evolve(hamiltonian, schedule, shots_count);
+      },
+      qpu_id);
path: runtime/cudaq/algorithms/evolve.h
user: login: khalatepradnya
body: Can you confirm that this call is non-blocking? I think we need to set `asyncExec` on `ExecutionContext` to `true` somewhere... perhaps this is handled by the `cudaq::__internal__::evolve_async`?
created_at: 2025-03-06T21:31:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <sstream>
+#include <stdexcept>
+
+namespace cudaq {
+rydberg_hamiltonian::rydberg_hamiltonian(
+    const std::vector<Coordinate> &atom_sites, const scalar_operator &amplitude,
+    const scalar_operator &phase, const scalar_operator &delta_global,
+    const std::vector<int> &atom_filling,
path: runtime/cudaq/dynamics/rydberg_hamiltonian.cpp
user: login: khalatepradnya
body: Should we make `atom_filling` optional as well? 
created_at: 2025-03-06T21:40:15Z
author_association: COLLABORATOR
diff_hunk: @@ -589,6 +589,52 @@ class product_operator {
   friend product_operator<T> operator_handler::identity(int target);
 };
 
+/// @brief Representation of a time-dependent Hamiltonian for Rydberg system
+class rydberg_hamiltonian {
+public:
+  using Coordinate = std::pair<double, double>;
path: runtime/cudaq/operators.h
user: login: khalatepradnya
body: Q: Is the casing on this been spec-approved? `Coordinate` v/s `coordinate`
created_at: 2025-03-06T21:41:58Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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. *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <gtest/gtest.h>
+
+using namespace cudaq;
+
+TEST(RydbergHamiltonianTest, ConstructorValidInputs) {
+  // Valid atom sites
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, ConstructorWithAtomFilling) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  std::vector<int> atom_filling = {1, 0, 1};
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                  atom_filling);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling(), atom_filling);
+}
+
+TEST(RydbergHamiltonianTest, InvalidAtomFillingSize) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid atom filling size
+  std::vector<int> atom_filling = {1, 0};
+
+  EXPECT_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                   atom_filling),
+               std::invalid_argument);
+}
+
+TEST(RydbergHamiltonianTest, UnsupportedLocalDetuning) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid delta_local
+  auto delta_local =
+      std::make_pair(scalar_operator(0.5), std::vector<double>{0.1, 0.2, 0.3});
+
+  EXPECT_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                   {}, delta_local),
+               std::runtime_error);
+}
+
+TEST(RydbergHamiltonianTest, Accessors) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites(), atom_sites);
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, DefaultAtomFilling) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  std::vector<int> expected_filling(atom_sites.size(), 1);
+  EXPECT_EQ(hamiltonian.get_atom_filling(), expected_filling);
+}
path: unittests/dynamics/rydberg_hamiltonian.cpp
user: login: khalatepradnya
body: Nice set of tests! 
created_at: 2025-03-06T21:43:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <sstream>
+#include <stdexcept>
+
+namespace cudaq {
+rydberg_hamiltonian::rydberg_hamiltonian(
+    const std::vector<Coordinate> &atom_sites, const scalar_operator &amplitude,
+    const scalar_operator &phase, const scalar_operator &delta_global,
+    const std::vector<int> &atom_filling,
path: runtime/cudaq/dynamics/rydberg_hamiltonian.cpp
user: login: khalatepradnya
body: Saw the tests cover this scenario.
created_at: 2025-03-06T21:43:52Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq {
+namespace __internal__ {
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt) {
+  auto amp = hamiltonian.get_amplitude();
+  auto ph = hamiltonian.get_phase();
+  auto dg = hamiltonian.get_delta_global();
+  std::vector<std::pair<double, double>> amp_ts;
+  std::vector<std::pair<double, double>> ph_ts;
+  std::vector<std::pair<double, double>> dg_ts;
+  for (const auto &step : schedule) {
+    auto amp_res = amp.evaluate({{"t", step}});
+    amp_ts.push_back(std::make_pair(amp_res.real(), step.real()));
+
+    auto ph_res = ph.evaluate({{"t", step}});
+    ph_ts.push_back(std::make_pair(ph_res.real(), step.real()));
+
+    auto dg_res = dg.evaluate({{"t", step}});
+    dg_ts.push_back(std::make_pair(dg_res.real(), step.real()));
+  }
+
+  auto atoms = cudaq::ahs::AtomArrangement();
+  for (auto pair : hamiltonian.get_atom_sites()) {
+    atoms.sites.push_back({pair.first, pair.second});
+  }
+  atoms.filling = hamiltonian.get_atom_filling();
+
+  auto omega = cudaq::ahs::PhysicalField();
+  omega.time_series = cudaq::ahs::TimeSeries(amp_ts);
+
+  auto phi = cudaq::ahs::PhysicalField();
+  phi.time_series = cudaq::ahs::TimeSeries(ph_ts);
+
+  auto delta = cudaq::ahs::PhysicalField();
+  delta.time_series = cudaq::ahs::TimeSeries(dg_ts);
+
+  auto drive = cudaq::ahs::DrivingField();
+  drive.amplitude = omega;
+  drive.phase = phi;
+  drive.detuning = delta;
+
+  auto program = cudaq::ahs::Program();
+  program.setup.ahs_register = atoms;
+  program.hamiltonian.drivingFields = {drive};
+  program.hamiltonian.localDetuning = {};
+
+  std::ostringstream programName;
+  programName << "__analog_hamiltonian_kernel__" << []() {
+    const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    std::random_device rd;
+    std::mt19937 generator(rd());
+    std::uniform_int_distribution<> distribution(0, chars.size() - 1);
+    std::string result;
+    result.reserve(10);
+    for (int i = 0; i < 10; ++i)
+      result += chars[distribution(generator)];
+    return result;
+  }();
+
+  auto programJson = nlohmann::json(program);
+
+  auto &platform = cudaq::get_platform();
+  auto ctx =
+      std::make_unique<ExecutionContext>("sample", shots_count.value_or(100));
+  ctx->asyncExec = false;
+  platform.set_exec_ctx(ctx.get());
+
+  auto programString = programJson.dump();
+  cudaq::info("Program JSON: {}", programString);
path: runtime/cudaq/dynamics/evolution.cpp
user: login: khalatepradnya
body: Observation - In my manual testing I found this resulted in a verbose output (while using logger of course), specifically when targeting Pasqal.
created_at: 2025-03-06T22:22:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+// Compile and run with:
+// ```
+// nvq++ --target pasqal pasqal.cpp -o out.x
+// ./out.x
+// ```
+// Assumes a valid set of credentials (PASQAL_AUTH_TOKEN, PASQAL_PROJECT_ID)
+// have been set.
+
+#include "cudaq/algorithms/evolve.h"
+#include "cudaq/dynamics_integrators.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
path: docs/sphinx/targets/cpp/pasqal.cpp
user: login: nvidia-dobri
body: I'll need to get back to this. Looks like all the dynamics examples also do this. Additionally, looks like we have a forward declaration in evolve that requires `dynamics_integrators` to be included even when unused, and that's pretty nasty. I already started working on the spec refactor, so let me address those there, it will be easier.
created_at: 2025-03-07T04:00:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -277,4 +277,25 @@ evolve_async(const HamTy &hamiltonian, const cudaq::dimension_map &dimensions,
              "recompile your application with '--target dynamics' flag.");
 #endif
 }
-} // namespace cudaq
\ No newline at end of file
+
+// Rydberg Hamiltonian
+evolve_result evolve(const cudaq::rydberg_hamiltonian &hamiltonian,
+                     const cudaq::schedule &schedule,
+                     std::optional<int> shots_count = std::nullopt) {
+  return cudaq::__internal__::evolveSingle(hamiltonian, schedule, shots_count);
+}
+
+async_evolve_result async_evolve(const cudaq::rydberg_hamiltonian &hamiltonian,
+                                 const cudaq::schedule &schedule,
+                                 std::optional<int> shots_count = std::nullopt,
+                                 int qpu_id = 0) {
+  return cudaq::__internal__::evolve_async(
+      [=]() {
+        ExecutionContext context("evolve");
+        cudaq::get_platform().set_exec_ctx(&context, qpu_id);
+        return evolve(hamiltonian, schedule, shots_count);
+      },
+      qpu_id);
path: runtime/cudaq/algorithms/evolve.h
user: login: nvidia-dobri
body: Yeah, that's what cudaq::__internal__::evolve_async does, essentially. I can't say I fully understand that this is the canonical correct way to do this, but it does work and it is async 🙂  I "borrowed" it from the existing dynamics implementation.
created_at: 2025-03-07T04:10:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -589,6 +589,52 @@ class product_operator {
   friend product_operator<T> operator_handler::identity(int target);
 };
 
+/// @brief Representation of a time-dependent Hamiltonian for Rydberg system
+class rydberg_hamiltonian {
+public:
+  using Coordinate = std::pair<double, double>;
path: runtime/cudaq/operators.h
user: login: nvidia-dobri
body: Fixed.
created_at: 2025-03-07T04:10:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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. *
+ ******************************************************************************/
+
+#include "cudaq/operators.h"
+#include <gtest/gtest.h>
+
+using namespace cudaq;
+
+TEST(RydbergHamiltonianTest, ConstructorValidInputs) {
+  // Valid atom sites
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, ConstructorWithAtomFilling) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Valid atom filling
+  std::vector<int> atom_filling = {1, 0, 1};
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                  atom_filling);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites().size(), atom_sites.size());
+  EXPECT_EQ(hamiltonian.get_atom_filling(), atom_filling);
+}
+
+TEST(RydbergHamiltonianTest, InvalidAtomFillingSize) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid atom filling size
+  std::vector<int> atom_filling = {1, 0};
+
+  EXPECT_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                   atom_filling),
+               std::invalid_argument);
+}
+
+TEST(RydbergHamiltonianTest, UnsupportedLocalDetuning) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  // Invalid delta_local
+  auto delta_local =
+      std::make_pair(scalar_operator(0.5), std::vector<double>{0.1, 0.2, 0.3});
+
+  EXPECT_THROW(rydberg_hamiltonian(atom_sites, amplitude, phase, delta_global,
+                                   {}, delta_local),
+               std::runtime_error);
+}
+
+TEST(RydbergHamiltonianTest, Accessors) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  EXPECT_EQ(hamiltonian.get_atom_sites(), atom_sites);
+  EXPECT_EQ(hamiltonian.get_amplitude().evaluate({}),
+            std::complex<double>(1.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_phase().evaluate({}),
+            std::complex<double>(0.0, 0.0));
+  EXPECT_EQ(hamiltonian.get_delta_global().evaluate({}),
+            std::complex<double>(-0.5, 0.0));
+}
+
+TEST(RydbergHamiltonianTest, DefaultAtomFilling) {
+  std::vector<rydberg_hamiltonian::Coordinate> atom_sites = {
+      {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
+
+  // Valid operators
+  scalar_operator amplitude(1.0);
+  scalar_operator phase(0.0);
+  scalar_operator delta_global(-0.5);
+
+  rydberg_hamiltonian hamiltonian(atom_sites, amplitude, phase, delta_global);
+
+  std::vector<int> expected_filling(atom_sites.size(), 1);
+  EXPECT_EQ(hamiltonian.get_atom_filling(), expected_filling);
+}
path: unittests/dynamics/rydberg_hamiltonian.cpp
user: login: nvidia-dobri
body: Would love to take credit, but these were already in the massive operators / dynamics PR, they just got dropped along the way 😅 
created_at: 2025-03-07T04:13:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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.    *
+ ******************************************************************************/
+
+#include "common/AnalogHamiltonian.h"
+#include "common/EvolveResult.h"
+#include "common/Logger.h"
+#include "cudaq/operators.h"
+#include "cudaq/schedule.h"
+#include <random>
+#include <sstream>
+#include <string>
+
+namespace cudaq {
+namespace __internal__ {
+
+evolve_result evolveSingle(const cudaq::rydberg_hamiltonian &hamiltonian,
+                           const cudaq::schedule &schedule,
+                           std::optional<int> shots_count = std::nullopt) {
+  auto amp = hamiltonian.get_amplitude();
+  auto ph = hamiltonian.get_phase();
+  auto dg = hamiltonian.get_delta_global();
+  std::vector<std::pair<double, double>> amp_ts;
+  std::vector<std::pair<double, double>> ph_ts;
+  std::vector<std::pair<double, double>> dg_ts;
+  for (const auto &step : schedule) {
+    auto amp_res = amp.evaluate({{"t", step}});
+    amp_ts.push_back(std::make_pair(amp_res.real(), step.real()));
+
+    auto ph_res = ph.evaluate({{"t", step}});
+    ph_ts.push_back(std::make_pair(ph_res.real(), step.real()));
+
+    auto dg_res = dg.evaluate({{"t", step}});
+    dg_ts.push_back(std::make_pair(dg_res.real(), step.real()));
+  }
+
+  auto atoms = cudaq::ahs::AtomArrangement();
+  for (auto pair : hamiltonian.get_atom_sites()) {
+    atoms.sites.push_back({pair.first, pair.second});
+  }
+  atoms.filling = hamiltonian.get_atom_filling();
+
+  auto omega = cudaq::ahs::PhysicalField();
+  omega.time_series = cudaq::ahs::TimeSeries(amp_ts);
+
+  auto phi = cudaq::ahs::PhysicalField();
+  phi.time_series = cudaq::ahs::TimeSeries(ph_ts);
+
+  auto delta = cudaq::ahs::PhysicalField();
+  delta.time_series = cudaq::ahs::TimeSeries(dg_ts);
+
+  auto drive = cudaq::ahs::DrivingField();
+  drive.amplitude = omega;
+  drive.phase = phi;
+  drive.detuning = delta;
+
+  auto program = cudaq::ahs::Program();
+  program.setup.ahs_register = atoms;
+  program.hamiltonian.drivingFields = {drive};
+  program.hamiltonian.localDetuning = {};
+
+  std::ostringstream programName;
+  programName << "__analog_hamiltonian_kernel__" << []() {
+    const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    std::random_device rd;
+    std::mt19937 generator(rd());
+    std::uniform_int_distribution<> distribution(0, chars.size() - 1);
+    std::string result;
+    result.reserve(10);
+    for (int i = 0; i < 10; ++i)
+      result += chars[distribution(generator)];
+    return result;
+  }();
+
+  auto programJson = nlohmann::json(program);
+
+  auto &platform = cudaq::get_platform();
+  auto ctx =
+      std::make_unique<ExecutionContext>("sample", shots_count.value_or(100));
+  ctx->asyncExec = false;
+  platform.set_exec_ctx(ctx.get());
+
+  auto programString = programJson.dump();
+  cudaq::info("Program JSON: {}", programString);
path: runtime/cudaq/dynamics/evolution.cpp
user: login: nvidia-dobri
body: Yeah, I'll switch this over to debug logging. I agree. I think at debug level, verbose/noisy is expected and I still think this is useful to be able to get easily.
created_at: 2025-03-07T04:14:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -706,6 +706,25 @@ jobs:
           export PASQAL_MACHINE_TARGET="EMU_FREE" # Speedup queuing time
           set +e # Allow script to keep going through errors
           test_err_sum=0
+          cpp_tests="docs/sphinx/targets/cpp/pasqal.cpp"
+          for filename in $cpp_tests; do
+            [ -e "$filename" ] || echo "::error::Couldn't find file ($filename)"
+            nvq++ --target pasqal $filename
path: .github/workflows/integration_tests.yml
user: login: khalatepradnya
body: ```suggestion
            nvq++ --target pasqal --pasqal-machine EMU_FREE $filename
```
to speed up queuing
created_at: 2025-03-07T06:11:06Z
author_association: COLLABORATOR
diff_hunk: @@ -702,6 +702,7 @@ jobs:
           python3 -m pip install pasqal-cloud
           export PASQAL_USERNAME='${{ secrets.PASQAL_USERNAME }}'
           export PASQAL_PASSWORD='${{ secrets.PASQAL_PASSWORD }}'
+          export PASQAL_AUTH_TOKEN=$(python3 docs/sphinx/targets/cpp/pasqal_auth.py)
path: .github/workflows/integration_tests.yml
user: login: khalatepradnya
body: Need to check that this new file will be available to this job, as in we don't have code that copies only `docs/sphinx/targets/cpp/*.cpp`... 
Edit: Looks good
created_at: 2025-03-07T22:25:49Z
author_association: COLLABORATOR
diff_hunk: @@ -702,6 +702,7 @@ jobs:
           python3 -m pip install pasqal-cloud
           export PASQAL_USERNAME='${{ secrets.PASQAL_USERNAME }}'
           export PASQAL_PASSWORD='${{ secrets.PASQAL_PASSWORD }}'
+          export PASQAL_AUTH_TOKEN=$(python3 docs/sphinx/targets/cpp/pasqal_auth.py)
path: .github/workflows/integration_tests.yml
user: login: khalatepradnya
body: The new file `docs/sphinx/targets/cpp/pasqal_auth.py` is incorrectly being treated as Python example by validation script and causing following failure in `Validate cuda-quantum image` stage:

```2025-03-07T22:48:28.8894236Z   File "/home/cudaq/targets/cpp/pasqal_auth.py", line 2, in <module>
2025-03-07T22:48:28.8894990Z     from pasqal_cloud import SDK
2025-03-07T22:48:28.8895320Z ModuleNotFoundError: No module named 'pasqal_cloud'
```
It needs to be skipped.
created_at: 2025-03-07T23:31:28Z
author_association: COLLABORATOR

PR comments:
user: login: copy-pr-bot[bot]
created_at: 2025-03-06T20:36:28Z
body: This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities [here](https://docs.gha-runners.nvidia.com/cpr/vetters).

Contributors can view more details about this message [here](https://docs.gha-runners.nvidia.com/cpr/contributors).

author_association: NONE
user: login: khalatepradnya
created_at: 2025-03-06T20:45:32Z
body: > /ok to test

**Command Bot:** Processing...
author_association: COLLABORATOR
user: login: khalatepradnya
created_at: 2025-03-06T21:53:01Z
body: We need a follow-up docs update PR to add the new examples for [Pasqal](https://nvidia.github.io/cuda-quantum/latest/using/backends/hardware/neutralatom.html#pasqal) and [QuEra](https://nvidia.github.io/cuda-quantum/latest/using/backends/hardware/neutralatom.html#quera-computing).
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-03-06T21:55:04Z
body: **CUDA Quantum Docs Bot:** A preview of the documentation can be found [here](https://htmlpreview.github.io/?https://github.com/NVIDIA/cuda-quantum/blob/docs/preview/pr-2704/index.html).
author_association: NONE
user: login: khalatepradnya
created_at: 2025-03-06T22:20:29Z
body: Manually tested examples for both Pasqal and QuEra.
(QuEra system was unavailable at the time of testing so checked payload and canceled job.)
Also tried Pasqal with `nvq++ --target pasqal --pasqal-machine EMU_FREE source.cpp`
author_association: COLLABORATOR
user: login: sacpis
created_at: 2025-03-07T14:32:21Z
body: > /ok to test

**Command Bot:** Processing...
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-03-07T15:42:52Z
body: **CUDA Quantum Docs Bot:** A preview of the documentation can be found [here](https://htmlpreview.github.io/?https://github.com/NVIDIA/cuda-quantum/blob/docs/preview/pr-2704/index.html).
author_association: NONE
user: login: nvidia-dobri
created_at: 2025-03-07T17:44:05Z
body: > /ok to test

**Command Bot:** Processing...
author_association: CONTRIBUTOR
user: login: khalatepradnya
created_at: 2025-03-07T18:16:28Z
body: > /ok to test

**Command Bot:** Processing...
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-03-07T19:57:17Z
body: **CUDA Quantum Docs Bot:** A preview of the documentation can be found [here](https://htmlpreview.github.io/?https://github.com/NVIDIA/cuda-quantum/blob/docs/preview/pr-2704/index.html).
author_association: NONE
user: login: nvidia-dobri
created_at: 2025-03-07T21:45:35Z
body: > /ok to test

**Command Bot:** Processing...
author_association: CONTRIBUTOR
user: login: nvidia-dobri
created_at: 2025-03-07T22:17:53Z
body: > /ok to test

**Command Bot:** Processing...
author_association: CONTRIBUTOR
user: login: nvidia-dobri
created_at: 2025-03-07T23:37:25Z
body: > /ok to test

**Command Bot:** Processing...
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-07T23:39:25Z
body: **CUDA Quantum Docs Bot:** A preview of the documentation can be found [here](https://htmlpreview.github.io/?https://github.com/NVIDIA/cuda-quantum/blob/docs/preview/pr-2704/index.html).
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-08T01:09:41Z
body: **CUDA Quantum Docs Bot:** A preview of the documentation can be found [here](https://htmlpreview.github.io/?https://github.com/NVIDIA/cuda-quantum/blob/docs/preview/pr-2704/index.html).
author_association: NONE