Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c0a09cb
qBraid integration MVP (#4)
ryanhill1 Jun 4, 2025
925ae39
update: migrate cudaq to platform v2
TheGupta2012 Mar 13, 2026
41fe248
fix: merge conflicts
TheGupta2012 Mar 13, 2026
d74243d
add: api_key and device to set_target for qbraid
TheGupta2012 Mar 13, 2026
9cd62cf
fix: submodule hashes and v2 platform implementation and test
TheGupta2012 Apr 15, 2026
3b0a1e4
fix: formatting and headers
TheGupta2012 Apr 15, 2026
1a24c66
fix: docs for qbraid helper and update examples
TheGupta2012 Apr 16, 2026
71b9450
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 16, 2026
31bde9e
DCO Remediation Commit for Harshit <harshit.11235@gmail.com>
TheGupta2012 Apr 17, 2026
61e4b91
DCO Remediation Commit for TheGupta2012 <harshit.11235@gmail.com>
TheGupta2012 Apr 17, 2026
f6ba810
fix: formatting issues, api key leak and default num of qubits
TheGupta2012 Apr 20, 2026
f4907ac
fix: headers to use 2026
TheGupta2012 Apr 20, 2026
a79cc61
fix: cmake list for qbraid to unconditionally include qbraid in the b…
TheGupta2012 Apr 21, 2026
38830db
fix: target tests for qbraid to use execution test pattern and make a…
TheGupta2012 Apr 21, 2026
39cfb72
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 21, 2026
89ed685
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 22, 2026
7ab08ec
fix: EADDRINUSE error in CI due to port collision with HorizonServerH…
TheGupta2012 Apr 22, 2026
9f43415
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 23, 2026
e43b46d
add: error handling for status codes in result fetch and correspondin…
TheGupta2012 Apr 23, 2026
967402c
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 24, 2026
c47f54a
fix: review comments, add combine meas and other codegen passes to re…
TheGupta2012 Apr 24, 2026
a525bfb
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 Apr 27, 2026
9262e69
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 May 1, 2026
2bc6bc5
Merge remote-tracking branch 'upstream/main' into migrate-cudaq-v2
ryanhill1 May 7, 2026
bcd43e5
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 May 9, 2026
2b65005
fix: login order for integration tests, ref PR #4486
TheGupta2012 May 9, 2026
ccb0c30
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 May 11, 2026
947982e
Merge branch 'main' into migrate-cudaq-v2
TheGupta2012 May 12, 2026
875d33a
fix: ci failures
TheGupta2012 May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/pre-commit/spelling_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ Photonics
PyPI
Pygments
QAOA
QASM
QBRAID
QCI
QCaaS
QEC
Expand Down Expand Up @@ -169,6 +171,7 @@ amongst
ancilla
ansatz
ansatzes
api
archiver
arity
auxillary
Expand Down Expand Up @@ -302,6 +305,7 @@ lossy
lvalue
macOS
makefiles
measurementCounts
merchantability
mps
multinomial
Expand All @@ -314,6 +318,7 @@ natively
normalization
nullary
nvcc
nvq
observables
optimizer
optimizers
Expand All @@ -335,21 +340,26 @@ preprocessor
probability
programmatically
pybind
qBraid
qaoa
qbraid
qed
qio
qrn
quantize
quantized
qubit
qubits
qudit
qudits
queryable
qumode
qumodes
reStructuredText
realtime
reconfigurable
reproducibility
resultData
reusability
runtime
runtimes
Expand Down
58 changes: 50 additions & 8 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ on:
- quantinuum
- scaleway
- tii
- qbraid
single_test_name:
type: string
required: false
Expand Down Expand Up @@ -95,6 +96,13 @@ jobs:
cudaq_test_image: ${{ steps.vars.outputs.cudaq_nightly_image }}@${{ steps.test_image.outputs.digest }}

steps:
- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}

- name: Set variables
id: vars
run: |
Expand All @@ -112,13 +120,6 @@ jobs:
echo "platforms=$(echo $platforms | tr ' ' ,)" >> $GITHUB_OUTPUT
echo "cudaq_nightly_image=$cudaq_nightly_image" >> $GITHUB_OUTPUT

- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}

- name: Set up context for buildx
run: |
docker context create builder_context
Expand Down Expand Up @@ -191,7 +192,7 @@ jobs:
run: |
# Determine which providers to test based on inputs and event type
if [[ "${{ github.event_name }}" == "schedule" || "${{ inputs.target }}" == "nightly" ]]; then
providers='["anyon", "fermioniq", "infleqtion", "ionq", "iqm", "oqc", "orca", "pasqal", "qci", "quantinuum", "scaleway", "tii"]'
providers='["anyon", "fermioniq", "infleqtion", "ionq", "iqm", "oqc", "orca", "pasqal", "qbraid", "qci", "quantinuum", "scaleway", "tii"]'
else
# Just run the specified target provider
providers="[\"${{ inputs.target }}\"]"
Expand Down Expand Up @@ -261,6 +262,9 @@ jobs:
pasqal)
filelist="docs/sphinx/targets/cpp/pasqal.cpp docs/sphinx/targets/python/pasqal.py"
;;
qbraid)
filelist="targettests/qbraid/*.cpp docs/sphinx/targets/cpp/qbraid.cpp docs/sphinx/targets/python/qbraid.py"
;;
qci)
filelist="targettests/qci/*.cpp"
;;
Expand Down Expand Up @@ -380,6 +384,11 @@ jobs:
echo "PASQAL_PROJECT_ID=${{ secrets.PASQAL_PROJECT_ID }}" >> $GITHUB_ENV
echo "PASQAL_MACHINE_TARGET=EMU_FREE" >> $GITHUB_ENV
;;
qbraid)
echo "### Setting up qBraid account" >> $GITHUB_STEP_SUMMARY
echo "::add-mask::${{ secrets.QBRAID_API_KEY }}"
echo "QBRAID_API_KEY=${{ secrets.QBRAID_API_KEY }}" >> $GITHUB_ENV
;;
qci)
echo "### Setting up QCI account" >> $GITHUB_STEP_SUMMARY
echo "::add-mask::${{ secrets.QCI_AUTH_TOKEN }}"
Expand Down Expand Up @@ -671,6 +680,39 @@ jobs:
fi
;;

qbraid)
if [[ "$filename" == *.cpp ]]; then
nvq++ -v $filename --target qbraid --qbraid-machine qbraid:qbraid:sim:qir-sv
test_status=$?
if [ $test_status -eq 0 ]; then
./a.out
test_status=$?
if [ $test_status -eq 0 ]; then
echo ":white_check_mark: Successfully ran test: $filename" >> $GITHUB_STEP_SUMMARY
else
echo ":x: Test failed (failed to execute): $filename" >> $GITHUB_STEP_SUMMARY
test_err_sum=$((test_err_sum+1))
fi
else
echo ":x: Test failed (failed to compile): $filename" >> $GITHUB_STEP_SUMMARY
test_err_sum=$((test_err_sum+1))
fi
elif [[ "$filename" == *.py ]]; then
python3 $filename 1> /dev/null
test_status=$?
if [ $test_status -eq 0 ]; then
echo ":white_check_mark: Successfully ran test: $filename" >> $GITHUB_STEP_SUMMARY
else
echo ":x: Test failed (failed to execute): $filename" >> $GITHUB_STEP_SUMMARY
test_err_sum=$((test_err_sum+1))
fi
else
echo "::warning::Unsupported file type: $filename"
echo ":warning: Test skipped (unsupported file type): $filename" >> $GITHUB_STEP_SUMMARY
test_skip_sum=$((test_skip_sum+1))
fi
;;

qci)
nvq++ -v $filename --target qci
test_status=$?
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ if (NOT DEFINED CUDAQ_ENABLE_SCALEWAY_BACKEND)
set(CUDAQ_ENABLE_SCALEWAY_BACKEND ON CACHE BOOL "Enable building the Scaleway target.")
endif()

# Enable qBraid target by default.
if (NOT DEFINED CUDAQ_ENABLE_QBRAID_BACKEND)
set(CUDAQ_ENABLE_QBRAID_BACKEND ON CACHE BOOL "Enable building the qBraid target.")
endif()

# Generate a CompilationDatabase (compile_commands.json file) for our build,
# for use by clang_complete, YouCompleteMe, etc.
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
Expand Down
48 changes: 48 additions & 0 deletions docs/sphinx/targets/cpp/qbraid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Compile and run with:
// ```
// nvq++ --target qbraid qbraid.cpp -o out.x && ./out.x
// ```
// This will submit the job to the qBraid ideal simulator target (default).

#include <cudaq.h>
#include <fstream>

// Define a simple quantum kernel to execute on qBraid.
struct ghz {
// Maximally entangled state between 5 qubits.
auto operator()() __qpu__ {
cudaq::qvector q(5);
h(q[0]);
for (int i = 0; i < 4; i++) {
x<cudaq::ctrl>(q[i], q[i + 1]);
}
auto result = mz(q);
}
};

int main() {
// Submit to qBraid asynchronously (e.g., continue executing
// code in the file until the job has been returned).
auto future = cudaq::sample_async(ghz{});
// ... classical code to execute in the meantime ...

// Can write the future to file:
{
std::ofstream out("saveMe.json");
out << future;
}

// Then come back and read it in later.
cudaq::async_result<cudaq::sample_result> readIn;
std::ifstream in("saveMe.json");
in >> readIn;

// Get the results of the read in future.
auto async_counts = readIn.get();
async_counts.dump();

// OR: Submit to qBraid synchronously (e.g., wait for the job
// result to be returned before proceeding).
auto counts = cudaq::sample(ghz{});
counts.dump();
}
51 changes: 51 additions & 0 deletions docs/sphinx/targets/python/qbraid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import cudaq

# You only have to set the target once! No need to redefine it
# for every execution call on your kernel.
# To use different targets in the same file, you must update
# it via another call to `cudaq.set_target()`
cudaq.set_target("qbraid")


# Create the kernel we'd like to execute on qBraid.
@cudaq.kernel
def kernel():
qvector = cudaq.qvector(2)
h(qvector[0])
x.ctrl(qvector[0], qvector[1])


# Execute on qBraid and print out the results.

# Option A:
# By using the asynchronous `cudaq.sample_async`, the remaining
# classical code will be executed while the job is being handled
# by qBraid. This is ideal when submitting via a queue over
# the cloud.
async_results = cudaq.sample_async(kernel)
# ... more classical code to run ...

# We can either retrieve the results later in the program with
# ```
# async_counts = async_results.get()
# ```
# or we can also write the job reference (`async_results`) to
# a file and load it later or from a different process.
file = open("future.txt", "w")
file.write(str(async_results))
file.close()

# We can later read the file content and retrieve the job
# information and results.
same_file = open("future.txt", "r")
retrieved_async_results = cudaq.AsyncSampleResult(str(same_file.read()))

counts = retrieved_async_results.get()
print(counts)

# Option B:
# By using the synchronous `cudaq.sample`, the execution of
# any remaining classical code in the file will occur only
# after the job has been returned from qBraid.
counts = cudaq.sample(kernel)
print(counts)
3 changes: 2 additions & 1 deletion docs/sphinx/using/backends/cloud.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CUDA-Q provides a number of options to access hardware resources (GPUs and QPUs)

.. toctree::
:maxdepth: 1

Amazon Braket (braket) <cloud/braket.rst>
Scaleway QaaS (scaleway) <cloud/scaleway.rst>
qBraid <cloud/qbraid.rst>
101 changes: 101 additions & 0 deletions docs/sphinx/using/backends/cloud/qbraid.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
qBraid
++++++

.. _qbraid-backend:

`qBraid <https://www.qbraid.com/>`__ is a cloud platform that brokers access to
quantum simulators and hardware from multiple vendors through a single API.
CUDA-Q can submit OpenQASM 2 jobs to any device exposed by the qBraid service.
See the `qBraid device catalog <https://account.qbraid.com/devices>`__ for the
set of simulators and QPUs currently available.

Setting Credentials
```````````````````

Generate an API key from your `qBraid account <https://account.qbraid.com/>`__
and export it as an environment variable:

.. code:: bash

export QBRAID_API_KEY="qbraid_generated_api_key"

Alternatively, the API key can be passed directly to ``cudaq.set_target`` via
the ``api_key`` argument (see below).

Submitting
``````````

.. tab:: Python

The target to which quantum kernels are submitted can be controlled with
the ``cudaq.set_target()`` function.

.. code:: python

cudaq.set_target("qbraid")

By default, jobs are submitted to the qBraid state vector simulator
(``qbraid:qbraid:sim:qir-sv``).

To specify a different qBraid device, set the ``machine`` parameter to its
qBraid device ID.

.. code:: python

cudaq.set_target("qbraid", machine="qbraid:qbraid:sim:qir-sv")

The API key can also be supplied inline instead of through the
``QBRAID_API_KEY`` environment variable.

.. code:: python

cudaq.set_target("qbraid", api_key="qbraid_generated_api_key")

qBraid devices are cloud-hosted, so local emulation via the ``emulate``
flag is not supported — all jobs are executed on the qBraid service.
To run without submitting to real hardware, select one of the qBraid
simulator devices (for example, ``qbraid:qbraid:sim:qir-sv``) via the
``machine`` argument.

The number of shots for a kernel execution can be set through the
``shots_count`` argument to ``cudaq.sample`` or ``cudaq.observe``. The
default is 1000.

.. code:: python

cudaq.sample(kernel, shots_count=10000)

.. tab:: C++

To target quantum kernel code for execution on qBraid, pass the flag
``--target qbraid`` to the ``nvq++`` compiler. By default jobs are
submitted to the qBraid state vector simulator
(``qbraid:qbraid:sim:qir-sv``).

.. code:: bash

nvq++ --target qbraid src.cpp

To execute kernels on a different device, pass ``--qbraid-machine`` with
the qBraid device ID:

.. code:: bash

nvq++ --target qbraid --qbraid-machine "qbraid:qbraid:sim:qir-sv" src.cpp

The API key can be passed explicitly with ``--qbraid-api_key`` instead of
being read from ``QBRAID_API_KEY``:

.. code:: bash

nvq++ --target qbraid --qbraid-api_key "qbraid_generated_api_key" src.cpp

qBraid devices are cloud-hosted, so the ``--emulate`` flag is not
supported for this target — all jobs are executed on the qBraid
service. To run without submitting to real hardware, pass
``--qbraid-machine`` with a qBraid simulator device ID (for example,
``qbraid:qbraid:sim:qir-sv``).

To see a complete example for using qBraid's backends, take a look at our
:doc:`Python examples <../../examples/examples>` and
:doc:`C++ examples <../../examples/examples>`.
Loading