Skip to content
Merged
14 changes: 13 additions & 1 deletion .github/workflows/python_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,24 @@ jobs:
image: wheel_validation:local
shell: bash
run: |
python${{ inputs.python_version }} -m pytest /tmp/tests/
python${{ inputs.python_version }} -m pytest --ignore /tmp/tests/backends /tmp/tests/
pytest_status=$?
if [ ! $pytest_status -eq 0 ]; then
echo "pytest status = " $pytest_status
exit 1
fi
apt-get update && apt-get install -y git
git clone https://github.com/nvidia/cuda-quantum
cd cuda-quantum
python${{ inputs.python_version }} -m pip install --user fastapi uvicorn llvmlite
for backendTest in /tmp/tests/backends/*.py; do
python${{ inputs.python_version }} -m pytest $backendTest
pytest_status=$?
if [ ! $pytest_status -eq 0 ]; then
echo "pytest $backendTest status = " $pytest_status
exit 1
fi
done

- name: Validate Python examples
run: |
Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/test_in_devenv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,21 @@ jobs:
run: |
cd $CUDAQ_REPO_ROOT
pip install . --user -vvv
python3 -m pytest python/tests/
python3 -m pytest --ignore python/tests/backends python/tests/
pytest_status=$?
if [ ! $pytest_status -eq 0 ]; then
echo "pytest status = " $pytest_status
exit 1
fi

fi
for backendTest in python/tests/backends/*.py; do
python3 -m pytest $backendTest
pytest_status=$?
if [ ! $pytest_status -eq 0 ]; then
echo "pytest $backendTest status = " $pytest_status
exit 1
fi
done

- name: Save environment
id: env_save
if: inputs.export_environment
Expand Down
3 changes: 3 additions & 0 deletions python/cudaq/_cudaq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ PYBIND11_MODULE(_pycudaq, mod) {
},
"");

mod.def("set_random_seed", &cudaq::set_random_seed,
"Provide the seed for backend quantum kernel simulation.");

auto mpiSubmodule = mod.def_submodule("mpi");
mpiSubmodule.def(
"initialize", []() { cudaq::mpi::initialize(); },
Expand Down
34 changes: 8 additions & 26 deletions python/tests/backends/test_IonQ.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,23 @@
import cudaq, pytest, os, time
from cudaq import spin
from multiprocessing import Process
try:
from utils.mock_qpu.ionq import startServer
except:
print("Mock qpu not available, skipping IonQ tests.")
# TODO: Once we remove the general skip below, it should go here.

pytest.skip(
"This file produces a segmentation fault on the CI but not locally. See https://github.com/NVIDIA/cuda-quantum/issues/303.",
allow_module_level=True)
from utils.mock_qpu.ionq import startServer

# Define the port for the mock server
port = 62455


def assert_close(want, got, tolerance=1.0e-5) -> bool:
return abs(want - got) < tolerance
def assert_close(got) -> bool:
return got < -1.5 and got > -1.9


@pytest.fixture(scope="session", autouse=True)
def startUpMockServer():
# TODO: Support passing credentials via config file
os.environ["IONQ_API_KEY"] = "00000000000000000000000000000000"
credsName = "{}/FakeConfig.config".format(os.environ["HOME"])
f = open(credsName, "w")
f.write("key: {}\nrefresh: {}\ntime: 0".format("hello", "rtoken"))
f.close()

# Set the targeted QPU
cudaq.set_target(
"ionq",
url="http://localhost:{}".format(port),
credentials=credsName,
url="http://localhost:{}".format(port)
)

# Launch the Mock Server
Expand All @@ -51,10 +36,8 @@ def startUpMockServer():

yield "Running the tests."

# Kill the server, remove the file
# Kill the server
p.terminate()
os.remove(credsName)


def test_ionq_sample():
# Create the kernel we'd like to execute on IonQ
Expand Down Expand Up @@ -119,14 +102,13 @@ def test_ionq_observe():

# Run the observe task on IonQ synchronously
res = cudaq.observe(kernel, hamiltonian, 0.59)
want_expectation_value = -1.71
assert assert_close(want_expectation_value, res.expectation_z(), 1e-2)
assert assert_close(res.expectation_z())

# Launch it asynchronously, enters the job into the queue
future = cudaq.observe_async(kernel, hamiltonian, 0.59)
# Retrieve the results (since we're on a mock server)
res = future.get()
assert assert_close(want_expectation_value, res.expectation_z(), 1e-2)
assert assert_close(res.expectation_z())

# Launch the job async, job goes in the queue, and
# we're free to dump the future to file
Expand All @@ -139,7 +121,7 @@ def test_ionq_observe():
# the results from the term job ids.
futureReadIn = cudaq.AsyncObserveResult(futureAsString, hamiltonian)
res = futureReadIn.get()
assert assert_close(want_expectation_value, res.expectation_z(), 1e-2)
assert assert_close(res.expectation_z())


# leave for gdb debugging
Expand Down
19 changes: 6 additions & 13 deletions python/tests/backends/test_Quantinuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,25 @@
import cudaq, pytest, os, time
from cudaq import spin
from multiprocessing import Process
try:
from utils.mock_qpu.quantinuum import startServer
except:
print("Mock qpu not available, skipping Quantinuum tests.")
# TODO: Once we remove the general skip below, it should go here.

pytest.skip(
"This file produces a segmentation fault on the CI but not locally. See https://github.com/NVIDIA/cuda-quantum/issues/303.",
allow_module_level=True)
from utils.mock_qpu.quantinuum import startServer

# Define the port for the mock server
port = 62454


def assert_close(got) -> bool:
return got < -1.1 and got > -2.2
return got < -1.5 and got > -1.9


@pytest.fixture(scope="session", autouse=True)
def startUpMockServer():
# We need a Fake Credentials Config file
credsName = '{}/FakeConfig.config'.format(os.environ["HOME"])
credsName = '{}/QuantinuumFakeConfig.config'.format(os.environ["HOME"])
f = open(credsName, 'w')
f.write('key: {}\nrefresh: {}\ntime: 0'.format("hello", "rtoken"))
f.close()

cudaq.set_random_seed(13)

# Set the targeted QPU
cudaq.set_target('quantinuum',
url='http://localhost:{}'.format(port),
Expand Down Expand Up @@ -67,6 +60,7 @@ def test_quantinuum_sample():
# server. In reality you'd probably not want to
# do this with the remote job queue.
counts = cudaq.sample(kernel)
counts.dump()
assert (len(counts) == 2)
assert ('00' in counts)
assert ('11' in counts)
Expand Down Expand Up @@ -115,7 +109,6 @@ def test_quantinuum_observe():

# Run the observe task on quantinuum synchronously
res = cudaq.observe(kernel, hamiltonian, .59)
want_expectation_value = -1.71
assert assert_close(res.expectation_z())

# Launch it asynchronously, enters the job into the queue
Expand Down
32 changes: 8 additions & 24 deletions python/tests/backends/test_Quantinuum_LocalEmulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,10 @@
import cudaq, pytest, os, time
from cudaq import spin
from multiprocessing import Process
try:
from utils.mock_qpu.quantinuum import startServer
except:
print("Mock qpu not available, skipping Quantinuum tests.")
# TODO: Once we remove the general skip below, it should go here.

pytest.skip(
"This file produces a segmentation fault on the CI but not locally. See also https://github.com/NVIDIA/cuda-quantum/issues/303.",
allow_module_level=True)

# Define the port for the mock server
port = 62448


def assert_close(want, got, tolerance=1.e-5) -> bool:
return abs(want - got) < tolerance
def assert_close(got) -> bool:
return got < -1.5 and got > -1.9


@pytest.fixture(scope="session", autouse=True)
Expand All @@ -39,19 +27,15 @@ def startUpMockServer():
# Set the targeted QPU
cudaq.set_target('quantinuum', emulate='true')

# Launch the Mock Server
p = Process(target=startServer, args=(port,))
p.start()
time.sleep(1)

yield "Running the tests."

# Kill the server, remove the file
p.terminate()
# remove the file
os.remove(credsName)


def test_quantinuum_sample():
cudaq.set_random_seed(13)

# Create the kernel we'd like to execute on Quantinuum
kernel = cudaq.make_kernel()
qubits = kernel.qalloc(2)
Expand Down Expand Up @@ -81,6 +65,7 @@ def test_quantinuum_sample():


def test_quantinuum_observe():
cudaq.set_random_seed(13)
# Create the parameterized ansatz
kernel, theta = cudaq.make_kernel(float)
qreg = kernel.qalloc(2)
Expand All @@ -94,14 +79,13 @@ def test_quantinuum_observe():

# Run the observe task on quantinuum synchronously
res = cudaq.observe(kernel, hamiltonian, .59, shots_count=100000)
want_expectation_value = -1.71
assert assert_close(want_expectation_value, res.expectation_z(), 1e-1)
assert assert_close(res.expectation_z())

# Launch it asynchronously, enters the job into the queue
future = cudaq.observe_async(kernel, hamiltonian, .59, shots_count=100000)
# Retrieve the results (since we're on a mock server)
res = future.get()
assert assert_close(want_expectation_value, res.expectation_z(), 1e-1)
assert assert_close(res.expectation_z())


# leave for gdb debugging
Expand Down
3 changes: 2 additions & 1 deletion python/utils/TestingUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

#include "TestingUtils.h"
#include "common/PluginUtils.h"
#include "cudaq.h"
#include "cudaq/platform.h"
#include "nvqir/CircuitSimulator.h"
#include <fstream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <regex>
#include <sstream>

namespace py = pybind11;

namespace nvqir {
Expand Down Expand Up @@ -43,6 +43,7 @@ void bindTestUtils(py::module &mod, LinkedLibraryHolder &holder) {
"initialize", [&](std::size_t numQubits, std::size_t numShots) {
cudaq::ExecutionContext *context =
new cudaq::ExecutionContext("sample", numShots);
cudaq::set_random_seed(13);
holder.getSimulator("qpp")->setExecutionContext(context);
return std::make_tuple(
holder.getSimulator("qpp")->allocateQubits(numQubits), context);
Expand Down
4 changes: 4 additions & 0 deletions runtime/cudaq.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ void unset_noise();
/// @brief Utility function for clearing the shots
void clear_shots(const std::size_t nShots);

/// @brief Set a seed for any random number
/// generators used in backend simulations.
void set_random_seed(std::size_t seed);

namespace mpi {

/// @brief Initialize MPI if available. This function
Expand Down
9 changes: 8 additions & 1 deletion runtime/cudaq/cudaq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

namespace nvqir {
void tearDownBeforeMPIFinalize();
}
void setRandomSeed(std::size_t);
} // namespace nvqir

namespace cudaq::mpi {

Expand Down Expand Up @@ -192,6 +193,10 @@ bool cudaq::__internal__::isLibraryMode(const std::string &kernelname) {

//===----------------------------------------------------------------------===//

namespace nvqir {
void setRandomSeed(std::size_t);
}

namespace cudaq {

/// @brief Global boolean that disables
Expand Down Expand Up @@ -267,6 +272,8 @@ void unset_noise() {
auto &platform = cudaq::get_platform();
platform.set_noise(nullptr);
}

void set_random_seed(std::size_t seed) { nvqir::setRandomSeed(seed); }
} // namespace cudaq

namespace cudaq::support {
Expand Down
4 changes: 4 additions & 0 deletions runtime/nvqir/CircuitSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class CircuitSimulator {
/// simulation strategies that support noise modeling.
virtual void setNoiseModel(cudaq::noise_model &noise) = 0;

virtual void setRandomSeed(std::size_t seed) {
// do nothing
}

/// @brief Compute the expected value of the given spin op
/// with respect to the current state, <psi | H | psi>.
virtual cudaq::ExecutionResult observe(const cudaq::spin_op &term) = 0;
Expand Down
6 changes: 6 additions & 0 deletions runtime/nvqir/NVQIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ CircuitSimulator *getCircuitSimulatorInternal() {
return simulator;
}

void setRandomSeed(std::size_t seed) {
getCircuitSimulatorInternal()->setRandomSeed(seed);
}

thread_local static bool isBaseProfile = false;
void toggleBaseProfile() { isBaseProfile = !isBaseProfile; }

Expand Down Expand Up @@ -364,6 +368,8 @@ Result *__quantum__qis__mz__to__register(Qubit *q, const char *name) {
return b ? ResultOne : ResultZero;
}

bool __quantum__qis__read_result__body(Result *r) { return false; }

void __quantum__rt__array_start_record_output() {}
void __quantum__rt__array_end_record_output() {}
void __quantum__rt__result_record_output(Result *, int8_t *) {}
Expand Down
Loading