Skip to content
Stefan J. Wernli edited this page May 31, 2024 · 17 revisions

Quantum Intermediate Representation (QIR) is a program representation based on LLVM IR. The specification is developed by the QIR Alliance.

QIR specifies different profiles for different hardware capabilities. The Q# compiler can generate QIR that is compatible with the 'Base' profile, which is limited to programs that can be represented as a sequence of operations. The compiler can also generate QIR that is compatible with the adaptive profile. The 'Adaptive_RI' profile allows additional capabilities such as mid-circuit measurement, branching based on measurement results or performing classical integer computations at runtime, and gets its name from the adaptive profile and two extensions: qubit reset support and integer computation.

Q# code that runs in the local simulator is not limited to any subset of QIR described in a 'profile'. We refer to this as Unrestricted. When developing Q# code, you can set the target profile via either the "Set the Azure Quantum QIR target profile" command (as shown below) or clicking on the editor status bar which will display the current target profile (either "QIR base", "Unrestricted" or "QIR Adaptive RI" if the experimental settings are enabled).

image

If the current program is not compatible with the selected target profile, you will get errors in the editor when targeting "QIR Base" or "QIR Adaptive RI". If the program is compatible, you can view the generated QIR via the "Get QIR for the current Q# program" menu item (also shown in the clipping above).

The following sections describe errors that can be encountered when compiling Q# with a specific profile, along with examples and possible mitigations. These errors come from the Runtime Capabilities Check pass that validates the capabilities used by the program are compatible with the capabilities of the configured target profile.

Runtime Capabilities Check Errors

Use of Dynamic Bool

Code: Qsc.CapabilitiesCk.UseOfDynamicBool

This indicates the program is using Boolean values that depend on qubit measurement when the configured target profile does not support Boolean variables. This usually occurs when compiling against the 'Base' profile, which does not allow for any branching based on measurement results. For example, the following code uses a dynamic bool to apply a gate operation to a qubit:

use q = Qubit();
H(q);
if M(q) == One {
    X(q);
}

The comparison of a measurement result to the literals One, Zero, or to another measurement result cannot be included in a program compiled for a target without support for Boolean variables.

Use of Dynamic Integer

Code: Qsc.CapabilitiesCk.UseOfDynamicInt

This indicates the program is using integer values that depend on qubit measurement when the configured target profile does not support integer variables. This can happen when compiling against target profiles that do not support the adaptive profile with the integer computation extension. For example, the following code calculates a dynamic integer:

mutable x = 0;
use qs = Qubit[3];
for q in qs {
    H(q);
    if M(q) == One {
        set x += 1;
    }
}

The use of integer computation that depends on measurement results cannot be included in a program compiled for a target that does not support integer variables and computation.

Use of Dynamic Pauli

Code: Qsc.CapabilitiesCk.UseOfDynamicPauli

This indicates the program is using a Pauli value that depends on qubit measurement when the configured target profile does not support Pauli variables. Which of the literal values PauliX, PauliY, PauliZ and PauliI a variable holds must be known at compile time to be considered static. For example, the following code uses a dynamic Pauli value:

use q = Qubit();
let p = if M(q) == One { PauliX } else { PauliI };
R(p, 3.14, q);

The use of Pauli variables whose value depends on a measurement result cannot be included in a program compiled for a target that does not support Pauli variables.

Use of Dynamic Range

Code: Qsc.CapabilitiesCk.UseOfDynamicRange

This indicates the program is using a Range value that depends on qubit measurement when the configured target profile does not support Range variables. A Range can be considered dynamic if either it uses a dynamic integer for one of the elements:

use q = Qubit();
let end = if M(q) == One { 1 } else { 2 };
let range = 0..end;

or if the choice between two static ranges is based on a dynamic value like a measurement result:

use q = Qubit();
let range = if M(q) == One { 0..1 } else { 0..2 };

The use of Range variables whose value depends on a measurement result cannot be included in a program compiled for a target that does not support Range variables.

Use of Dynamic Double

Code: Qsc.CapabilitiesCk.UseOfDynamicDouble

This indicates the program is using floating point values that depend on qubit measurement when the configured target profile does not support floating point variables. This can happen when compiling against target profiles that do not support the adaptive profile with the floating point computation extension. For example, the following code calculates a dynamic Double:

mutable x = 0.0;
use qs = Qubit[3];
for q in qs {
    H(q);
    if M(q) == One {
        set x += 1.0;
    }
}

The use of floating point computation that depends on measurement results cannot be included in a program compiled for a target that does not support floating point variables and computation.

Use of Dynamic Qubit

Code: Qsc.CapabilitiesCk.UseOfDynamicQubit

This indicates the program is using a qubit whose identifier depends on a qubit measurement when the configured target profile does not support dyanmic qubit addressing. Most targets require static qubit identifiers, where the each qubit used is statically known at compile time. A qubit variable set based on a measurement result cannot be statically identified at each point of the program, such as this example:

use (q0, q1, q2) = (Qubit(), Qubit(), Qubit());
let chosen_q = if M(q0) == One { q1 } else { q2 };

The use of dynamic qubit identifiers cannot be included in a program compiled for a target that only supports static qubit identifiers.

Use of Dynamic Result

Code: Qsc.CapabilitiesCk.UseOfDynamicResult

This indicates the program is using a result whose identifier depends on a qubit measurement when the configured target profile does not support dyanmic result addressing. Most targets require static result identifiers, where the each result value used is statically known at compile time. A result variable conditionally updated based on a measurement result cannot be statically identified at each point of the program, such as this example:

use q = Qubit();
mutable res = M(q);
if res == One {
    set res = M(q);
}

The use of dynamic result identifiers cannot be included in a program compiled for a target that only supports static result identifiers. If the configured target profile supports dynamic Boolean or integer values, try using those instead. For example:

use q = Qubit();
mutable res = M(q) == One;
if res {
    set res = M(q) == One;
}

Use of Dynamic Tuple

Code: Qsc.CapabilitiesCk.UseOfDynamicTuple

Use of Dynamic Big Integer

Code: Qsc.CapabilitiesCk.UseOfDynamicBigInt

Use of Dynamic String

Code: Qsc.CapabilitiesCk.UseOfDynamicString

Use of Dynamic Exponent

Code: Qsc.CapabilitiesCk.UseOfDynamicExponent

Use of Dynamically-Sized Array

Code: Qsc.CapabilitiesCk.UseOfDynamicallSizedArray

Use of Dynamic User-Defined Type

Code: Qsc.CapabilitiesCk.UseOfDynamicUdt

Use of Dynamic Function

Code: Qsc.CapabilitiesCk.UseOfDynamicArrowFunction

Use of Dynamic Operation

Code: Qsc.CapabilitiesCk.UseOfDynamicArrowOperation

Call to Cyclic Function with Dynamic Argument

Code: Qsc.CapabilitiesCk.CallToCyclicFunctionWithDynamicArg

Cyclic Operation Definition

Code: Qsc.CapabilitiesCk.CyclicOperationSpec

Call to Cyclic Operation

Code: `Qsc.CapabilitiesCk.CallToCyclicOperation

Call to Dynamic Callee

Code: Qsc.CapabilitiesCk.CallToDynamicCallee

Measurement Within a Dynamic Scope

Code: Qsc.CapabilitiesCk.MeasurementWithinDynamicScope

Use of Dynamic Array Index

Code: Qsc.CapabilitiesCk.UseOfDynamicIndex

Return Within a Dynamic Scope

Code: `Qsc.CapabilitiesCk.ReturnWithinDynamicScope

Loop with Dynamic Condition

Code: Qsc.CapabilitiesCk.LoopWithDynamicCondition

Use of Bool Output

Code: Qsc.CapabilitiesCk.UseOfBoolOutput

Use of Double Output

Code: Qsc.CapabilitiesCk.UseOfDoubleOutput

Use of Integer Output

Code: Qsc.CapabilitiesCk.UseOfIntOutput

Use of Advanced Output

Code: Qsc.CapabilitiesCk.UseOfAdvancedOutput