Q Sharp
Q# (pronounced "Q sharp") is a high-level, open-source programming language developed by Microsoft specifically for writing and executing quantum algorithms, enabling the integration of quantum and classical computing within a single program. It provides abstractions for qubit management, quantum operations like superposition and entanglement, and measurement, while enforcing quantum physical constraints such as the no-cloning theorem to prevent invalid operations. As part of the Quantum Development Kit (QDK), Q# supports simulation on classical hardware and execution on diverse quantum processors via Azure Quantum, making it hardware-agnostic and accessible for developers exploring quantum applications. As of 2025, it supports execution on emerging hardware including Microsoft's topological qubits via Azure Quantum.[1]
Microsoft initially released Q# on December 11, 2017, as a free preview alongside the Quantum Development Kit, aiming to lower barriers for quantum programming by offering a familiar, imperative syntax similar to C# but tailored for quantum contexts.[2] The language was designed from the ground up for quantum computing, incorporating native types for qubits and results, as well as support for namespaces and entry points to structure complex quantum workflows.[2] In May 2019, Microsoft open-sourced key components of Q#, including the compiler and simulators, under the MIT License, fostering community contributions through its GitHub repository.[3]
Key features of Q# include seamless interoperability with classical languages like C# and Python, allowing quantum routines to call classical functions for hybrid algorithms, and built-in tools for resource estimation to analyze scalability for algorithms requiring up to millions of qubits without full simulation.[1] It supports advanced quantum constructs, such as adjoint and controlled operations for efficient algorithm implementation.[1] Q# has been used in notable quantum research, including simulations of quantum chemistry and optimization problems, and integrates with Azure Quantum's ecosystem for access to hardware from partners like IonQ and Quantinuum.[1]
Overview
Purpose and Scope
Q# is a standalone, domain-specific programming language developed by Microsoft specifically for expressing quantum algorithms in a hardware-agnostic manner.[4] As part of the Quantum Development Kit (QDK), it enables developers to manage qubits while adhering to the principles of quantum physics, such as superposition and entanglement, without tying implementations to specific quantum hardware architectures.[1]
The primary scope of Q# encompasses the writing, simulation, and execution of quantum programs that seamlessly integrate with classical computing code, facilitating hybrid quantum-classical workflows.[1] This integration allows for the orchestration of quantum operations alongside classical logic, resource estimation, and error handling, making it suitable for developing scalable quantum applications on both simulators and real quantum devices.[4]
Q# targets quantum algorithm designers, researchers, and developers who aim to bridge classical and quantum computing paradigms, from novices exploring quantum concepts to experts building complex protocols.[1] Its high-level goals include promoting scalable quantum software development by abstracting away low-level hardware complexities, thereby accelerating innovation in quantum algorithm design and deployment across diverse quantum computing ecosystems.[4]
Core Principles
Q# embodies a set of core design principles aimed at enabling developers to express quantum algorithms in a manner that is both intuitive and robust, prioritizing abstraction from underlying hardware complexities while enforcing quantum-specific constraints.[5] One foundational principle is hardware agnosticism, which allows the same Q# program to execute unmodified across diverse targets, including classical simulators, noisy intermediate-scale quantum (NISQ) devices, and future fault-tolerant quantum hardware. The Q# compiler and runtime system handle the mapping of abstract qubits in the program to physical qubits on the target machine, abstracting away hardware-specific details such as qubit topology, error correction, and gate decompositions.[1] This approach ensures scalability, as algorithms can be developed and tested on simulators before deployment to actual quantum processors without requiring code alterations.[5]
Another key principle is strong static typing, which provides compile-time checks to prevent common quantum programming errors, such as operations on invalid qubit states or type mismatches between classical and quantum data. Q# employs a minimalist type system with built-in types like Int, Bool, [Qubit](/page/Qubit), and Result, where variables are immutable by default unless explicitly declared mutable, and the compiler enforces type safety throughout the program.[6] This static analysis catches issues like attempting to reuse a measured qubit or applying incompatible operations, thereby reducing runtime errors and facilitating the development of reliable quantum software.[6]
Q# adopts an imperative programming style augmented with functional elements to allow safe and expressive definition of quantum operations, balancing the sequential control flow needed for hybrid quantum-classical algorithms with the composability required for reusable quantum subroutines. Developers can use imperative constructs like loops (for, repeat-until), conditionals (if), and mutable state for classical computations, while functional features such as first-class functions and operations, partial application, and adjoint/control functors enable the construction of modular quantum routines.[1] This hybrid paradigm supports the expression of complex algorithms, like quantum phase estimation, where imperative orchestration interleaves with functional composition of unitary operations.[5]
Central to Q#'s design is the emphasis on explicit qubit lifecycle management, which enforces fundamental quantum rules such as no-cloning and the irreversibility of measurement through structured allocation, usage, and deallocation. Qubits are allocated using the use statement (e.g., use q = Qubit();), which reserves quantum memory initialized to the |0⟩ state and scopes the qubit's lifetime to the enclosing block, ensuring automatic deallocation via Reset to |0⟩ upon exit to prevent leakage of quantum information.[7] During usage, operations like gates and measurements are applied within this scope, with the type system and runtime prohibiting cloning by treating qubits as opaque references that cannot be duplicated, and measurements collapsing states probabilistically while invalidating further superposition-based operations on the measured qubit.[7] This managed approach minimizes errors from improper state handling and supports efficient resource use, including "dirty ancillas" for temporary computations that are reset before release.[5]
History
Initial Development
Q# was publicly announced on September 25, 2017, during the keynote address by Microsoft CEO Satya Nadella at the Microsoft Ignite conference in Orlando, Florida.[8] This introduction highlighted Microsoft's commitment to advancing quantum computing accessibility for developers, positioning Q# as a novel programming language tailored for quantum algorithm design.[9]
The creation of Q# stemmed from the need for a high-level language to enable scalable quantum software development, particularly to program topological qubits that inherently incorporate error correction for improved stability and reliability.[10] Microsoft's research emphasized addressing scalability challenges in quantum systems, where traditional low-level approaches proved insufficient for complex, fault-tolerant computations.[8] The early development was led by the Microsoft Quantum team, with principal researcher Krysta M. Svore at the forefront, building on foundational work in quantum error correction pioneered within Microsoft's Station Q research group.[10]
On December 11, 2017, Microsoft released the initial preview of Q# as a core component of the Quantum Development Kit (QDK), which also featured a full-state quantum simulator and Visual Studio integration to facilitate experimentation without hardware.[10] This launch marked the first widely available toolset for quantum programming, aimed at fostering a developer community to explore applications in fields like materials science and optimization.
Major Milestones
In 2019, Microsoft open-sourced the Quantum Development Kit, including the Q# compiler and quantum simulators, under the MIT license, which facilitated broader community involvement and contributions through the official GitHub repository.[11] This move enabled developers worldwide to access, modify, and extend the core components of Q#, accelerating innovation in quantum software ecosystems.
The introduction of the Quantum Intermediate Representation (QIR) in 2020 marked a significant advancement in Q#'s interoperability, providing a hardware- and language-agnostic intermediate format based on LLVM to bridge quantum programming languages with diverse execution backends.[12] QIR allows Q# programs to be compiled into a standardized form, supporting optimizations and integration with tools from partners in the QIR Alliance, thereby enhancing portability across quantum hardware providers.[13]
In January 2024, Microsoft released version 1.0 of the Azure Quantum Development Kit, featuring a significant rewrite emphasizing modularity, performance improvements, and enhanced support for Q# development.[14]
By 2024 and into 2025, Azure Quantum's integration with Q# saw substantial enhancements, enabling seamless execution of Q# code on advanced hardware from providers such as IonQ and Quantinuum, including support for high-fidelity trapped-ion systems like Quantinuum's H2 series (56 qubits) and IonQ systems achieving up to #AQ 64 algorithmic qubits (as of September 2025).[15][16][17] Quantinuum's Helios system, launched in November 2025, offers improvements in qubit count (up to 98 qubits) and error correction for Q#-based applications.[18]
In February 2025, Microsoft unveiled Majorana 1, the world's first quantum processor powered by topological qubits, marking a breakthrough toward fault-tolerant quantum computing compatible with Q# programs.[19]
As of 2022, the development of λ-Q#, a theoretical core calculus for Q#, provided a formal foundation for language verification and refinement, modeling Q# as a simply typed λ-calculus augmented with quantum operations to ensure semantic precision and support future evolutions.[4] This formalism aids in proving properties of quantum algorithms and guides refinements in Q#'s design, contributing to more robust implementations by 2025.[20]
Design and Features
Language Paradigms
Q# is a multi-paradigm programming language that integrates imperative and functional styles to support both quantum control and classical computations. The imperative paradigm enables direct manipulation of quantum states, such as applying gates to qubits, allowing developers to express algorithms step-by-step in a manner familiar to classical programmers.[1][21] In contrast, the functional paradigm emphasizes pure expressions and higher-order functions for composing complex computations without side effects, facilitating abstraction and reusability in algorithm design.[1][21]
A key distinction in Q# lies between operations and functions, which delineate the boundaries between effectful quantum procedures and pure classical logic. Operations serve as the primary mechanism for quantum programming, permitting side effects like qubit allocation, gate applications, and measurements, while adhering to a controlled environment that ensures safe interaction with quantum hardware.[1][21] Functions, on the other hand, are restricted to deterministic, side-effect-free calculations, typically used for classical subroutines such as mathematical computations or conditionals that do not involve quantum resources.[1][21] This separation promotes clarity and prevents unintended quantum state modifications in classical code paths.[21]
To enhance modularity and code organization, Q# employs namespaces, which encapsulate related definitions and prevent naming conflicts across large programs. Standard libraries, such as Microsoft.Quantum.Intrinsic, are automatically imported and provide foundational operations and functions for common quantum primitives like gate applications and qubit management, enabling developers to build upon a robust ecosystem without reinventing core components.[1][21]
Error handling in Q# is integrated through failure conditions within quantum operations, enforcing physical constraints to maintain program correctness. For example, operations that allocate qubits must ensure their proper reset or release before completion; failure to do so triggers runtime exceptions, safeguarding against invalid quantum states or resource leaks.[1] This mechanism aligns with the language's emphasis on reliability in quantum environments, where non-compliance with quantum rules can lead to simulation or hardware failures.[1]
Quantum-Specific Capabilities
Q# provides specialized mechanisms for qubit allocation and management to ensure safe and scoped handling of quantum resources. Qubits are allocated within a local scope using the use keyword, which declares a variable of type Qubit initialized to the |0⟩ state, such as use q = Qubit(); for a single qubit or use qs = Qubit[2]; for an array.[1] This scoping automatically releases the qubits at the end of the block, but programmers must explicitly reset them to |0⟩ using the Reset operation to prevent runtime errors from residual entanglement.[1] For managing classical variables that interact with quantum states, such as measurement outcomes, the mutable keyword allows reassignment within scopes, enabling updates like mutable count = 0; set count += 1;.[1]
The language includes built-in intrinsic operations for fundamental quantum gates and measurements, facilitating direct manipulation of quantum states. The Hadamard gate H creates superposition by applying a balanced rotation to a qubit, transforming |0⟩ to (|0⟩ + |1⟩)/√2.[1] The controlled-NOT gate CNOT(control, target) entangles qubits by flipping the target qubit if the control is in |1⟩, essential for generating correlated states like Bell pairs.[22] Measurement is performed via the M operation, which collapses a qubit in the computational basis to a Result value (Zero or One), inherently handling interference by projecting superpositions onto classical outcomes.[1]
Superposition, entanglement, and interference are managed through these operations and extended by Q#'s functor system. The Adjoint functor inverts unitary operations (U†), enabling uncomputation to preserve qubit states and mitigate errors in reversible computations, while the Controlled functor conditions application on auxiliary control qubits in |1⟩, directly supporting entanglement construction across multiple qubits.[23] These functors apply to any compatible operation, allowing interference patterns to emerge from constructive and destructive combinations in circuit execution.[23]
Operations in Q# can be declared as adjointable and controllable using the Adj and Ctl characteristics, respectively, which enable automatic generation of specialized variants for the functors.[24] An operation signature like (Qubit => Unit is Adj + Ctl) indicates support for both, allowing optimizations such as adjoint self-inverse properties ((U†)† = U) and controlled parallelism in simulations or hardware executions.[24] This design promotes efficient circuit construction and resource management in quantum algorithms.[23]
Integration Mechanisms
Q# facilitates hybrid quantum-classical programs by embedding quantum operations within classical control flows, enabling developers to leverage existing .NET ecosystems for comprehensive computations. Operations in Q# can invoke classical functions defined in the language itself, which handle deterministic computations without quantum resources, while the broader program structure integrates with .NET-compatible hosts written in C# or F# to manage inputs, outputs, and simulation. This design allows Q# code to interact seamlessly with .NET libraries through the host application, where classical logic orchestrates quantum calls and processes results, supporting scalable hybrid workflows.[1]
For interoperability with Python, Q# supports direct integration via the IQ# kernel, which enables execution of Q# snippets within Python environments, particularly in Jupyter Notebooks using the %%qsharp magic command after importing the qsharp package. This setup allows Python scripts to call Q# operations as functions, passing classical data to and from quantum routines for interactive development and prototyping of hybrid algorithms. The azure-quantum package further extends this by facilitating submission of Q# jobs to Azure Quantum targets from Python hosts.[25][26]
Q# provides hooks for resource estimation and simulation through dedicated tools and APIs, allowing developers to interface with classical simulators without executing quantum hardware. The Azure Quantum Resource Estimator, invoked via Q# programs or command-line tools, analyzes operation sequences to predict qubit requirements, gate counts, and runtime costs across various hardware targets, aiding in feasibility assessments. Simulation occurs via .NET-based emulators like the full-state simulator, where Q# code hooks into classical backends for tracing, debugging, and performance profiling during development.[1][27]
Standalone execution of Q# programs is enabled by marking operations with the @EntryPoint() attribute, designating them as the starting point for compilation and runtime invocation. This attribute, applied to an operation like @EntryPoint() [operation](/page/Operation) Main() : [Unit](/page/Unit), compiles the Q# namespace into an executable .NET assembly, allowing direct runs via dotnet run without a separate host, while still supporting hybrid extensions through configurable profiles such as adaptive runtime for mid-circuit measurements.[28]
Usage
The Azure Quantum Development Kit (QDK) serves as the core toolkit for developing Q# programs, providing an open-source set of libraries, templates, and tools for building, simulating, and debugging quantum applications. It includes the Q# compiler, standard libraries for quantum operations, and project templates for creating hybrid classical-quantum solutions. Developers can install the QDK via the .NET SDK and NuGet packages, enabling seamless integration with classical .NET code.[29][30]
Q# offers robust IDE support through integrations with Visual Studio and Visual Studio Code. In Visual Studio, Q# projects can be created and managed using the full .NET project system, supporting compilation, building, and basic debugging. Visual Studio Code, via the QDK extension, provides advanced features including syntax highlighting, IntelliSense for code completion, error diagnostics, and integrated debugging with breakpoints and step-through execution. The Q# language server powers these capabilities, ensuring real-time feedback on code validity and quantum-specific constructs during development.[30][31]
For exploratory development, Q# integrates with Jupyter Notebooks through Python interoperability, allowing developers to embed Q# snippets within Python code using the qsharp magic package. This setup enables interactive simulation, visualization of quantum circuits, and rapid prototyping of hybrid programs directly in notebooks, with support for running on local simulators or submitting to Azure Quantum.[30]
Testing in Q# emphasizes verification of quantum operations through simulation, leveraging the QDK's local full-state simulator to execute programs multiple times and analyze probabilistic outcomes. Unit tests are implemented using the @Test attribute on parameterless operations, which appear in the VS Code Testing explorer for automated execution. Assertions on measurements include functions like Fact for Boolean checks, fail for explicit error termination, CheckZero to verify a qubit is in the |0⟩ state, and CheckAllZero for multi-qubit arrays, ensuring operations behave as expected under quantum constraints. These tools facilitate deterministic testing for small systems and statistical validation for larger ones.[32][33]
Execution Environments
Q# programs can be executed in various environments, primarily through simulators for development and testing, as well as on actual quantum hardware via cloud services. The primary simulation option is the full-state simulator provided by the Quantum Development Kit (QDK), which maintains the complete quantum state vector during execution. This simulator supports up to 32 qubits on local machines, limited by memory constraints where each qubit doubles the state space size, typically requiring around 64 GB of RAM for 32 qubits. On Azure Quantum, dense full-state simulations can extend to 40 qubits, leveraging cloud resources for larger-scale testing.[34][1]
For resource analysis without full simulation, the Azure Quantum Resource Estimator tool evaluates the qubit, gate, and runtime requirements of a Q# program on fault-tolerant quantum architectures. It models the entire quantum computing stack, including application logic, compilation overhead, and hardware parameters like error rates and quantum error correction schemes, producing estimates for physical and logical resources. This open-source tool accepts Q# input directly and supports customizable configurations to explore trade-offs, such as between qubit count and execution time, without executing the quantum operations.[35][36]
Hardware execution of Q# programs is facilitated through the Azure Quantum service, which allows submission to diverse quantum providers after compilation. As of 2025, supported providers include IonQ, offering trapped-ion systems with up to 36 qubits on its Forte series hardware and GPU-accelerated simulators, and Quantinuum, providing high-fidelity trapped-ion processors with full qubit connectivity, mid-circuit measurements, and emulators modeling System Model H2 noise. Programs are queued and executed on these backends, with results returned to the user, enabling scalable hybrid quantum-classical workflows.[37][16]
To enable cross-platform and hardware-agnostic execution, Q# compiles to Quantum Intermediate Representation (QIR), an extension of the LLVM intermediate language. QIR represents quantum operations as LLVM functions, allowing optimizations like circuit decomposition and integration with classical code, while targeting diverse backends such as simulators or providers like IonQ and Quantinuum. This LLVM-based format supports interoperability across quantum ecosystems, facilitating execution on various platforms without vendor lock-in.[38][39]
Syntax
Fundamental Elements
Q# programs are stored in files with the .qs extension, which allows for the organization of code into modular units.[1] Each file may contain one or more namespace declarations using the syntax namespace Name { ... }, where Name follows identifier rules such as dot-separated legal symbols; if no namespace is declared, the compiler defaults to the filename as the namespace name.[40] Namespaces serve to group related declarations like operations, functions, and types, and they can span multiple files without implying hierarchy—for instance, Foo and Foo.Bar are treated as distinct.[40]
The language supports a range of types as fundamental building blocks for data representation. Primitive types include Int for integers, Bool for boolean values, and Double for floating-point numbers, providing the basis for classical computations.[41] Quantum-specific types encompass Qubit to represent quantum bits, Result to denote measurement outcomes such as Zero or One, and Pauli for Pauli operators like PauliX, PauliY, or PauliZ.[41] User-defined types can be created using struct declarations, which define immutable named-item structures, such as a Complex struct with fields Real: Double and Imaginary: Double; these support copy-and-update expressions for modification without altering the original.[41]
Operations form the core executable units in Q#, declared with the syntax operation Name(parameters) : ReturnType { [body](/page/Body) }, where Name is the operation's identifier, parameters lists input types and names (optional if none), ReturnType specifies the output (or Unit for void), and body contains the statements to execute.[1] For example:
qsharp
[operation](/page/Operation) SayHello() : [Unit](/page/Unit) {
Message("Hello, Q#!");
}
[operation](/page/Operation) SayHello() : [Unit](/page/Unit) {
Message("Hello, Q#!");
}
This declares an operation named SayHello that takes no parameters, returns nothing, and outputs a message.[1]
Comments in Q# enhance code readability and documentation. Single-line comments begin with // and extend to the end of the line, usable anywhere in the code.[42] Documentation comments, prefixed with ///, precede type or callable declarations to generate API documentation in Markdown format, supporting sections like /// # Summary for overviews or /// # Example for code snippets.[42]
Attributes provide metadata to operations and other declarations, applied using @AttributeName() syntax before the declaration. The @EntryPoint() attribute designates a specific operation as the program's starting point for execution.[1] For instance:
qsharp
@EntryPoint()
operation GetRandomBit() : Result {
use q = Qubit();
H(q);
return M(q);
}
@EntryPoint()
operation GetRandomBit() : Result {
use q = Qubit();
H(q);
return M(q);
}
This marks GetRandomBit as the entry point, enabling direct invocation by the runtime.[1]
Similarities to Classical Languages
Q# draws significant syntactic and structural influences from C#, particularly in its use of curly braces to define code blocks such as namespaces, operations, and control structures, which mirrors the block delimitation common in C# for readability and scoping.[1] Semicolons in Q# are optional, used only to separate multiple statements on the same line, allowing for cleaner code when statements span new lines, a flexibility that departs slightly from C#'s stricter requirement but enhances familiarity for developers accustomed to varied classical conventions.[43] Operations in Q#, which encapsulate reusable quantum and classical logic with inputs, outputs, and bodies, function similarly to class methods in C#, enabling modular, class-like organization without full object-oriented inheritance.[1]
From F#, Q# adopts a functional programming style, evident in its emphasis on immutable variables declared with the let keyword and higher-order functions that treat operations as first-class citizens, facilitating composable code patterns akin to those in functional paradigms.[5] Pattern matching appears in select expressions, such as tuple deconstruction in for loops (e.g., for (index, value) in data { ... }), allowing concise handling of structured data much like F#'s pattern matching constructs for safer and more expressive code.[44]
Shared imperative elements across both C# and F# are prominent in Q#'s control flow, including variable scoping that confines bindings to their declaring block or enclosing scopes, promoting predictable visibility similar to block-scoped variables in classical languages.[45] Loops like for iterate over ranges or arrays in a manner reminiscent of C#'s foreach or F#'s sequence comprehensions, while conditional loops using repeat { ... } until (condition) provide while-like repetition for indeterminate iterations.[44] Conditionals employ standard if (condition) { ... } else { ... } syntax, directly paralleling imperative branching in C# and F# for straightforward decision-making.[46]
Q# further aligns with C# and F# through support for type inference, leveraging a Hindley-Milner-based system to automatically deduce types within callable bodies while requiring explicit annotations at top-level declarations, balancing convenience with precision in a way that echoes F#'s strong inference capabilities and C#'s local inference features.[47] Generics are integrated via type parameters on callables (e.g., operation Process<T>(input: T) : Unit), enabling reusable code over multiple types much like C#'s generic classes and methods or F#'s parameterized modules, though currently limited to callable definitions without full type parameterization in variables.[6]
Quantum Extensions
Q# introduces syntax extensions tailored to quantum computing, enabling direct manipulation of qubits and quantum operations while maintaining a classical-like structure for control flow. Central to these extensions is qubit handling, where qubits are allocated using the use statement to ensure proper scoping and automatic deallocation. For instance, a single qubit is allocated as use q = Qubit();, initializing it in the |0⟩ state, while an array of qubits uses use qubits = Qubit[n]; for n qubits. This allocation mechanism abstracts hardware details, allowing the Q# runtime to manage qubit resources across simulators and real devices.[1]
Immutable results from quantum operations, such as measurements, are bound using the let statement, promoting functional programming principles in quantum contexts. Measurement occurs via the intrinsic M operation, which projects a qubit onto the Z-basis and returns a Result value of Zero or One; for example, let result = M(q); captures the outcome without modifying the qubit directly. To prepare qubits for reuse or deallocation, the Reset operation sets a qubit back to |0⟩, as in Reset(q);, preventing runtime errors from unreset qubits on quantum hardware. These constructs ensure deterministic handling of non-deterministic quantum outcomes.[1]
Quantum gates and operations in Q# are applied through intrinsic calls for standard gates or user-defined operations, with syntax resembling function calls but extended for quantum composability. Intrinsic gates like the Hadamard gate are invoked directly, such as H(q);, which applies a π/2 rotation to create superposition. User-defined operations can be specialized for quantum properties using the is Adj + Ctl declaration, indicating support for adjoint (hermitian conjugate) and controlled variants; for example, an operation declared as operation MyOp(q : [Qubit](/page/Qubit)) : [Unit](/page/Unit) is Adj + Ctl { body } allows functor applications like Adjoint MyOp(q); to execute the inverse transformation.[48]
The controlled and adjoint functors further extend gate application by enabling conditional and reversible quantum operations without redundant code. The Controlled functor applies an operation only if all control qubits are in the |1⟩ state, using syntax like Controlled MyOp(cs, (q)); where cs is a Qubit[] array of controls. Similarly, the Adjoint functor inverts the operation, as in Adjoint MyOp(q);, and both functors commute, allowing combinations such as Controlled Adjoint MyOp(cs, (q)); for efficient multi-qubit gates like controlled-NOT or phase estimation. These modifiers support the construction of complex quantum circuits from modular, composable primitives.[23]
Examples
Basic Quantum Circuit
A basic quantum circuit in Q# demonstrates fundamental quantum operations by creating a Bell state, which exemplifies superposition and entanglement using two qubits. This example allocates two qubits, applies a Hadamard gate to the first qubit to induce superposition, and then uses a controlled-NOT (CNOT) gate to entangle them, followed by measurement to observe the correlated results.[49]
The following Q# operation implements this circuit:
qsharp
operation CreateBellState() : (Result, Result) {
use (q1, q2) = (Qubit(), Qubit());
H(q1);
CNOT(q1, q2);
let m1 = M(q1);
let m2 = M(q2);
return (m1, m2);
}
operation CreateBellState() : (Result, Result) {
use (q1, q2) = (Qubit(), Qubit());
H(q1);
CNOT(q1, q2);
let m1 = M(q1);
let m2 = M(q2);
return (m1, m2);
}
This code begins by allocating two fresh qubits using the use statement, which initializes them in the |0⟩ state and ensures automatic cleanup after the operation. The Hadamard gate H(q1) is then applied to the first qubit, transforming it from |0⟩ to the superposition state (1/√2)(|0⟩ + |1⟩), while the second qubit remains |0⟩, resulting in the joint state (1/√2)(|00⟩ + |10⟩). Next, the CNOT gate CNOT(q1, q2) entangles the qubits by flipping the second qubit if the first is |1⟩, yielding the Bell state (1/√2)(|00⟩ + |11⟩). Finally, the Pauli-Z measurement M is performed on each qubit, collapsing the state and returning the results as Zero or One.[49][50]
When executed multiple times on a quantum simulator, the measurements exhibit perfect correlation: the outcomes are always (Zero, Zero) or (One, One), each occurring with approximately 50% probability, demonstrating the entanglement where the state of one qubit is instantaneously linked to the other, regardless of distance. This probabilistic nature arises from the superposition before measurement, confirming the non-classical correlations of the Bell state.[49][50]
Hybrid Classical-Quantum Program
A hybrid classical-quantum program in Q# demonstrates the seamless integration of classical control flow with quantum computations, allowing classical logic to orchestrate multiple quantum oracle invocations for enhanced efficiency. One illustrative example is a variant of Grover's search algorithm, where a classical loop iteratively calls a quantum oracle to amplify the probability of measuring the marked state in an unsorted search space. This approach leverages Q#'s ability to embed quantum operations within classical structures, such as functions for preprocessing inputs and post-processing measurement outcomes.[51]
The following Q# code snippet implements this hybrid variant for a search problem with 5 qubits, where the classical function CalculateOptimalIterations processes the qubit count to determine the number of iterations, a quantum operation GroverSearch performs the search via a loop that invokes the oracle ReflectAboutMarked, and measurements are returned for classical analysis:
q
function CalculateOptimalIterations(nQubits : [Int](/page/INT)) : [Int](/page/INT) {
if nQubits > 63 { fail "This sample supports at most 63 [qubit](/page/Qubit)s."; }
let nItems = 1 <<< nQubits;
let angle = ArcSin(1. / Sqrt(IntAsDouble(nItems)));
let iterations = Round(0.25 * PI() / angle - 0.5);
return iterations;
}
operation ReflectAboutMarked(inputQubits : Qubit[]) : Unit is Adj + Ctl {
use outputQubit = Qubit();
within {
X(outputQubit); H(outputQubit);
for q in inputQubits[0..2..] { X(q); }
} apply { Controlled X(inputQubits, outputQubit); }
}
operation GroverSearch(nQubits : Int, iterations : Int, phaseOracle : (Qubit[] => Unit is Adj + Ctl)) : Result[] {
use qubits = Qubit[nQubits];
PrepareUniform(qubits);
for _ in 1..iterations {
phaseOracle(qubits);
ReflectAboutUniform(qubits);
}
[return](/page/Return) MResetEachZ(qubits);
}
operation Main() : Result[] {
let nQubits = 5;
let iterations = CalculateOptimalIterations(nQubits);
Message($"Number of iterations: {iterations}");
let results = GroverSearch(nQubits, iterations, ReflectAboutMarked);
return results;
}
function CalculateOptimalIterations(nQubits : [Int](/page/INT)) : [Int](/page/INT) {
if nQubits > 63 { fail "This sample supports at most 63 [qubit](/page/Qubit)s."; }
let nItems = 1 <<< nQubits;
let angle = ArcSin(1. / Sqrt(IntAsDouble(nItems)));
let iterations = Round(0.25 * PI() / angle - 0.5);
return iterations;
}
operation ReflectAboutMarked(inputQubits : Qubit[]) : Unit is Adj + Ctl {
use outputQubit = Qubit();
within {
X(outputQubit); H(outputQubit);
for q in inputQubits[0..2..] { X(q); }
} apply { Controlled X(inputQubits, outputQubit); }
}
operation GroverSearch(nQubits : Int, iterations : Int, phaseOracle : (Qubit[] => Unit is Adj + Ctl)) : Result[] {
use qubits = Qubit[nQubits];
PrepareUniform(qubits);
for _ in 1..iterations {
phaseOracle(qubits);
ReflectAboutUniform(qubits);
}
[return](/page/Return) MResetEachZ(qubits);
}
operation Main() : Result[] {
let nQubits = 5;
let iterations = CalculateOptimalIterations(nQubits);
Message($"Number of iterations: {iterations}");
let results = GroverSearch(nQubits, iterations, ReflectAboutMarked);
return results;
}
In this program, quantum measurements from MResetEachZ produce a Result[] array that feeds directly into classical post-processing, such as verifying the marked state (e.g., alternating 0s and 1s for the oracle) or aggregating outcomes across runs for statistical analysis. Error handling is incorporated classically via the fail statement in CalculateOptimalIterations to prevent invalid qubit allocations exceeding simulator limits, ensuring robust execution. This hybrid flow highlights how classical decisions, like loop counts derived from qubit scaling, dynamically control quantum amplification steps.[51]
For simulation, this program runs in the Q# Development Kit (QDK) using the in-memory quantum simulator, which supports up to 63 qubits and integrates with classical .NET environments for seamless execution and debugging. The simulator handles qubit allocation and measurement collapse classically while preserving quantum superposition during oracle calls, allowing developers to test hybrid workflows without hardware.[51]