Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions lib/Optimizer/Transforms/QuakeAddMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace {

/// Define a type to contain the Quake Function Metadata
struct QuakeMetadata {
bool hasMeasurements = false;
bool hasConditionalsOnMeasure = false;

// If the following flag is set, it means we've detected quantum to classical
Expand Down Expand Up @@ -99,6 +100,13 @@ struct QuakeFunctionAnalysis {
LLVM_DEBUG(llvm::dbgs()
<< "Function to analyze: " << funcOp.getName() << '\n');
QuakeMetadata data;

// Check for any measurements
funcOp->walk([&](quake::MeasurementInterface meas) {
data.hasMeasurements = true;
return WalkResult::interrupt();
});

SmallPtrSet<Operation *, 8> dirtySet;
funcOp->walk([&](quake::DiscriminateOp disc) {
dirtySet.insert(disc.getOperation());
Expand Down Expand Up @@ -209,6 +217,11 @@ class QuakeAddMetadataPass
assert(iter != funcAnalysisInfo.end());
const auto &info = iter->second;

if (info.hasMeasurements) {
auto builder = OpBuilder::atBlockBegin(&funcOp.getBody().front());
funcOp->setAttr("hasMeasurements", builder.getBoolAttr(true));
}

// Did this function have conditionals on measures?
if (info.hasConditionalsOnMeasure) {
// if so, add a function attribute
Expand Down
18 changes: 10 additions & 8 deletions lib/Optimizer/Transforms/QuakePropagateMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class QuakePropagateMetadataPass
/// positives. expand-measurements and loop-unrolling may further reduce
/// false positives.
void runOnOperation() override {
static const std::vector<StringRef> attributesToPropagate = {
"qubitMeasurementFeedback", "hasMeasurements"};
ModuleOp moduleOp = getOperation();
/// NOTE: If the module has an occurrence of `quake.apply` then the step to
/// build call graph fails. Hence, we skip the pass in such cases.
Expand Down Expand Up @@ -90,15 +92,15 @@ class QuakePropagateMetadataPass
LLVM_DEBUG(llvm::dbgs()
<< "Visiting callee: " << callee.getName() << "\n\n");
for (auto caller : callers) {

LLVM_DEBUG(llvm::dbgs() << " Caller: " << caller.getName() << "\n\n");
if (auto boolAttr = callee->getAttr("qubitMeasurementFeedback")
.dyn_cast_or_null<mlir::BoolAttr>()) {
if (boolAttr.getValue()) {
LLVM_DEBUG(llvm::dbgs()
<< " Propagating qubitMeasurementFeedback attr: "
<< boolAttr << "\n");
caller->setAttr("qubitMeasurementFeedback", boolAttr);
for (auto attribute : attributesToPropagate) {
if (auto boolAttr = callee->getAttr(attribute)
.dyn_cast_or_null<mlir::BoolAttr>()) {
if (boolAttr.getValue()) {
LLVM_DEBUG(llvm::dbgs() << " Propagating " << attribute
<< " attr: " << boolAttr << "\n");
caller->setAttr(attribute, boolAttr);
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions python/cudaq/kernel/kernel_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ def __init__(self, argTypeList):
cc.register_dialect(context=self.ctx)
cudaq_runtime.registerLLVMDialectTranslation(self.ctx)

self.hasMeasurements = False
self.conditionalOnMeasure = False
self.regCounter = 0
self.loc = Location.unknown(context=self.ctx)
Expand Down Expand Up @@ -1135,6 +1136,7 @@ def mz(self, target, regName=None):
kernel.mz(target=qubit))
```
"""
self.hasMeasurements = True
with self.ctx, self.insertPoint, self.loc:
i1Ty = IntegerType.get_signless(1)
qubitTy = target.mlirValue.type
Expand Down Expand Up @@ -1182,6 +1184,7 @@ def mx(self, target, regName=None):
kernel.mx(qubit))
```
"""
self.hasMeasurements = True
with self.ctx, self.insertPoint, self.loc:
i1Ty = IntegerType.get_signless(1)
qubitTy = target.mlirValue.type
Expand Down Expand Up @@ -1230,6 +1233,7 @@ def my(self, target, regName=None):
kernel.my(qubit))
```
"""
self.hasMeasurements = True
with self.ctx, self.insertPoint, self.loc:
i1Ty = IntegerType.get_signless(1)
qubitTy = target.mlirValue.type
Expand Down
32 changes: 27 additions & 5 deletions python/cudaq/runtime/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def sample(kernel,
or a list of such results in the case of `sample` function broadcasting.
"""

has_measurements = False
has_conditionals_on_measure_result = False

if isinstance(kernel, PyKernelDecorator):
Expand All @@ -85,20 +86,41 @@ def sample(kernel,
if not hasattr(operation, 'name'):
continue
if nvqppPrefix + kernel.name == operation.name.value:
has_measurements = 'hasMeasurements' in operation.attributes
has_conditionals_on_measure_result = 'qubitMeasurementFeedback' in operation.attributes
break
elif isinstance(kernel, PyKernel) and kernel.conditionalOnMeasure:
has_conditionals_on_measure_result = True
elif isinstance(kernel, PyKernel):
if kernel.hasMeasurements:
has_measurements = True
if kernel.conditionalOnMeasure:
has_conditionals_on_measure_result = True

if explicit_measurements:
if not cudaq_runtime.supportsExplicitMeasurements():
raise RuntimeError(
"The sampling option `explicit_measurements` is not supported on this target."
)
"The sampling option `explicit_measurements` is not supported "
"on this target.")
if has_conditionals_on_measure_result:
raise RuntimeError(
"The sampling option `explicit_measurements` is not supported on kernel with conditional logic on a measurement result."
"The sampling option `explicit_measurements` is not supported "
"on kernel with conditional logic on a measurement result.")
if has_measurements:
if cudaq_runtime.isQuantumDevice():
raise RuntimeError(
"Kernels with explicit measurement operations cannot be used with "
"`cudaq.sample` on hardware targets. Please remove all measurements "
"from the kernel, qubits will be automatically measured at the end "
"when sampling a kernel.\n"
"Alternatively, use `cudaq.run` API, if supported on this target."
)
elif not explicit_measurements:
print(
"WARNING: Using `cudaq.sample` with a kernel that contains explicit "
"measurements is deprecated and will be disallowed in a future release. "
"Please remove all measurements from the kernel, qubits will be "
"automatically measured at the end when sampling a kernel.\n"
"Alternatively, use `cudaq.run` API which preserves individual "
"measurement results.")

if noise_model != None:
cudaq_runtime.set_noise(noise_model)
Expand Down
7 changes: 7 additions & 0 deletions runtime/common/DeviceCodeRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,11 @@ bool kernelHasConditionalFeedback(const std::string &kernelName) {
return !quakeCode.empty() &&
quakeCode.find("qubitMeasurementFeedback = true") != std::string::npos;
}

bool kernelHasMeasurements(const std::string &kernelName) {
auto quakeCode = get_quake_by_name(kernelName, false);
return !quakeCode.empty() &&
quakeCode.find("hasMeasurements = true") != std::string::npos;
}

} // namespace cudaq
2 changes: 2 additions & 0 deletions runtime/cudaq.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ KernelArgsCreator getArgsCreator(const std::string &kernelName);

bool kernelHasConditionalFeedback(const std::string &kernelName);

bool kernelHasMeasurements(const std::string &kernelName);

/// @brief Provide a hook to set the target backend.
void set_target_backend(const char *backend);

Expand Down
26 changes: 26 additions & 0 deletions runtime/cudaq/algorithms/sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace cudaq {
bool kernelHasConditionalFeedback(const std::string &);
bool kernelHasMeasurements(const std::string &);
namespace detail {
bool isKernelGenerated(const std::string &);
}
Expand Down Expand Up @@ -99,6 +100,31 @@ runSampling(KernelFunctor &&wrappedKernel, quantum_platform &platform,
auto isQuantumDevice =
!isRemoteSimulator && (platform.is_remote() || platform.is_emulated());

auto hasMeasurements = cudaq::kernelHasMeasurements(kernelName);
if (hasMeasurements) {
if (isQuantumDevice) {
// Hardware: Error immediately
throw std::runtime_error(
"Kernels with explicit measurement operations cannot be used with "
"`cudaq::sample` on hardware targets. Please remove all "
"measurements from the kernel, qubits will be automatically measured "
"at the end when sampling a kernel."
"Alternatively, use `cudaq::run` API, if supported on this target.");
} else {
// Simulators: Warning for now, but indicate future deprecation
if (!explicitMeasurements) {
printf(
"WARNING: Using `cudaq::sample` with a kernel that contains "
"explicit measurements is deprecated and will be disallowed in a "
"future release. Please remove all measurements from the kernel, "
"qubits will be automatically measured at the end when sampling a "
"kernel.\n"
"Alternatively, use `cudaq::run` which preserves individual "
"measurement results.");
}
}
}

// Loop until all shots are returned.
cudaq::sample_result counts;
while (counts.get_total_shots() < static_cast<std::size_t>(shots)) {
Expand Down
Loading