-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Some prototyping code * Prototype * Revise the noise model * Add example * Update docstring: * Code refactor * Add tests * Code format * Add Python tests * Code format * Support custom op - For the path via ExecutionManager: making sure the registration is early enough, i.e., at the point of registration. - For the Python path: need to let the registry know about the registration. - Propagate the custom op name all the way to the simulator. * Fix a lit test * Add docs * Fix remote test * Fix spelling * Add a C++ example
- Loading branch information
Showing
25 changed files
with
1,203 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Compile and run with: | ||
// ``` | ||
// nvq++ noise_callback.cpp --target density-matrix-cpu -o dyn.x | ||
// && ./dyn.x | ||
// ``` | ||
// | ||
// Note: You must set the target to a density matrix backend for the noise | ||
// to successfully impact the system. | ||
|
||
#include <cudaq.h> | ||
#include <iostream> | ||
|
||
// CUDA-Q supports several different models of noise. In this | ||
// case, we will examine the dynamic noise channel specified as a callback | ||
// function. | ||
|
||
int main() { | ||
|
||
// We will begin by defining an empty noise model that we will add | ||
// our channel to. | ||
cudaq::noise_model noise; | ||
// Noise model callback function | ||
const auto rx_noise = [](const auto &qubits, | ||
const auto ¶ms) -> cudaq::kraus_channel { | ||
// Model a pulse-length based rotation gate: | ||
// the bigger the angle, the longer the pulse, i.e., more amplitude damping. | ||
auto angle = params[0]; | ||
// Normalize the angle into the [0, 2*pi] range | ||
while (angle > 2. * M_PI) | ||
angle -= 2. * M_PI; | ||
|
||
while (angle < 0) | ||
angle += 2. * M_PI; | ||
// Damping rate is linearly proportional to the angle | ||
const auto damping_rate = angle / (2. * M_PI); | ||
std::cout << "Angle = " << params[0] | ||
<< ", amplitude damping rate = " << damping_rate << "\n"; | ||
return cudaq::amplitude_damping_channel(damping_rate); | ||
}; | ||
|
||
// Bind the noise model callback function to the `rx` gate | ||
noise.add_channel<cudaq::types::rx>(rx_noise); | ||
|
||
auto kernel = [](double angle) __qpu__ { | ||
cudaq::qubit q; | ||
rx(angle, q); | ||
mz(q); | ||
}; | ||
|
||
// Now let's set the noise and we're ready to run the simulation! | ||
cudaq::set_noise(noise); | ||
|
||
// Our results should show measurements in both the |0> and |1> states, | ||
// indicating that the noise has successfully impacted the system. Note: a | ||
// `rx(pi)` is equivalent to a Pauli X gate, and thus, it should be in the |1> | ||
// state if no noise is present. | ||
auto noisy_counts = cudaq::sample(kernel, M_PI); | ||
std::cout << "Noisy result:\n"; | ||
noisy_counts.dump(); | ||
|
||
// To confirm this, we can run the simulation again without noise. | ||
cudaq::unset_noise(); | ||
auto noiseless_counts = cudaq::sample(kernel, M_PI); | ||
std::cout << "Noiseless result:\n"; | ||
noiseless_counts.dump(); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import cudaq | ||
import numpy as np | ||
|
||
# Set the target to our density matrix simulator. | ||
cudaq.set_target('density-matrix-cpu') | ||
|
||
noise = cudaq.NoiseModel() | ||
|
||
|
||
# Noise model callback function | ||
def rx_noise(qubits, params): | ||
# Model a pulse-length based rotation gate: | ||
# the bigger the angle, the longer the pulse, i.e., more amplitude damping. | ||
angle = params[0] | ||
angle = angle % (2 * np.pi) | ||
# Damping rate is linearly proportional to the angle | ||
damping_rate = np.abs(angle / (2 * np.pi)) | ||
print(f"Angle = {angle}, amplitude damping rate = {damping_rate}.") | ||
return cudaq.AmplitudeDampingChannel(damping_rate) | ||
|
||
|
||
# Bind the noise model callback function to the `rx` gate | ||
noise.add_channel('rx', rx_noise) | ||
|
||
|
||
@cudaq.kernel | ||
def kernel(angle: float): | ||
qubit = cudaq.qubit() | ||
rx(angle, qubit) | ||
mz(qubit) | ||
|
||
|
||
# Now we're ready to run the noisy simulation of our kernel. | ||
# Note: We must pass the noise model to sample via keyword. | ||
noisy_result = cudaq.sample(kernel, np.pi, noise_model=noise) | ||
print(noisy_result) | ||
|
||
# Our results should show measurements in both the |0> and |1> states, indicating | ||
# that the noise has successfully impacted the system. | ||
# Note: a `rx(pi)` is equivalent to a Pauli X gate, and thus, it should be | ||
# in the |1> state if no noise is present. | ||
|
||
# To confirm this, we can run the simulation again without noise. | ||
noiseless_result = cudaq.sample(kernel, np.pi) | ||
print(noiseless_result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 - 2024 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 "py_CustomOpRegistry.h" | ||
#include "common/CustomOp.h" | ||
#include <pybind11/complex.h> | ||
#include <pybind11/functional.h> | ||
#include <pybind11/stl.h> | ||
|
||
namespace cudaq { | ||
struct py_unitary_operation : public unitary_operation { | ||
std::vector<std::complex<double>> | ||
unitary(const std::vector<double> ¶meters = | ||
std::vector<double>()) const override { | ||
throw std::runtime_error("Attempt to invoke the placeholder for Python " | ||
"unitary op. This is illegal."); | ||
return {}; | ||
} | ||
}; | ||
|
||
void bindCustomOpRegistry(py::module &mod) { | ||
mod.def( | ||
"register_custom_operation", | ||
[&](const std::string &opName) { | ||
cudaq::customOpRegistry::getInstance() | ||
.registerOperation<py_unitary_operation>(opName); | ||
}, | ||
"Register a custom operation"); | ||
} | ||
} // namespace cudaq |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/****************************************************************-*- C++ -*-**** | ||
* Copyright (c) 2022 - 2024 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 <pybind11/pybind11.h> | ||
|
||
namespace py = pybind11; | ||
|
||
namespace cudaq { | ||
/// @brief Bind the custom operation registry to Python. | ||
void bindCustomOpRegistry(py::module &mod); | ||
} // namespace cudaq |
Oops, something went wrong.