Tutorial: Explore quantum entanglement with Q#
Note
The examples in this topic use the Microsoft Quantum Development Kit (Classic QDK) and are not yet compatible with the Azure Quantum Development Kit Preview (Modern QDK). For more information about the Modern QDK, see the QSharp GitHub Wiki.
This tutorial shows you how to write a Q# program that manipulates and measures qubits and demonstrates the effects of superposition and entanglement.
- Where classical bits hold a single binary value such as a 0 or 1, the state of a qubit can be in a superposition of two quantum states, 0 and 1. Each possible quantum state has an associated probability amplitude.
- The act of measuring a qubit produces a binary result with a certain probability, and changes the state of the qubit out of superposition.
- Multiple qubits can be entangled such that they can't be described independently from each other. That is, whatever happens to one qubit in an entangled pair also happens to the other qubit.
Tip
If you want to accelerate your quantum computing journey, check out the Copilot in Azure Quantum, a unique feature of the Azure Quantum website. With the Copilot you can run your Q# programs, generate new Q# code from your prompts, and ask any questions about quantum computing.
In this tutorial, you prepare two qubits in a specific quantum state, learn how to operate on qubits with Q# to change their state, and demonstrate the effects of superposition and entanglement. You build your Q# program piece-by-piece to introduce qubit states, operations, and measurements.
Prerequisites
To complete this tutorial, you'll need:
- An Azure account with an active subscription. If you don’t have an Azure account, register for free and sign up for a pay-as-you-go subscription.
- An Azure Quantum workspace. For more information, see Create an Azure Quantum workspace.
In this tutorial, you'll learn how to
- Create Q# operations to measure and initialize a qubit to a desired state.
- Create qubits and test your program.
- Put a qubit in superposition.
- Entangle a pair of qubits.
Create a new Notebook in your workspace
- Log in to the Azure portal and select the workspace you created in the previous step.
- In the left blade, select Notebooks.
- Click My Notebooks and click Add New.
- In Kernel Type, select IQ#.
- Type a name for the file, for example Entanglement.ipynb, and click Create file.
When your new Notebook opens, it automatically creates the code for the first cell, based on your subscription and workspace information.
%azure.connect "/subscriptions/\<subscription ID>/\<resource group>/providers/Microsoft.Quantum/Workspaces/\<workspace>" \<location>
Note
%azure.connect is an IQ# Magic command, a set of commands that help streamline tasks in Jupyter Notebooks.
If you run this cell, it should authenticate to your subscription and display a list of available providers and their targets.
Initialize a qubit using measurement
The first step is to define a Q# operation that initializes a qubit to a known state. You call this to set a qubit to a classical state, meaning it either returns Zero
100% of the time or returns One
100% of the time. Zero
and One
are Q# values that represent the only two possible results of a measurement of a qubit.
Click +Code to add a new cell and add the following code:
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
Note
The Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
namespaces, which are used by operations in this code, are automatically opened in every cell of an Azure Quantum notebook.
The code example introduces two standard operations, M
and X
, which transform the state of a qubit.
The SetQubitState
operation:
- Takes two parameters: a type
Result
, nameddesired
, that represents the desired state for the qubit to be in (0 or 1), and a typeQubit
. - Performs a measurement operation,
M
, which measures the state of the qubit (Zero
orOne
) and compares the result to the value specified indesired
. - If the measurement does not match the compared value, it runs an
X
operation, which flips the state of the qubit to where the probabilities of a measurement returningZero
andOne
are reversed. This way,SetQubitState
always puts the target qubit in the desired state.
Test the measurement
Next, to demonstrate the effect of the SetQubitState
operation, create another operation named TestBellState
.
Add another new cell and add the following code:
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones':
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Return number of |0> states, number of |1> states
Message("q1:Zero, One q2:Zero, One");
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
The TestBellState
operation:
- Takes two parameters:
count
, the number of times to run a measurement, andinitial
, the desired state to initialize the qubit. - Calls the
use
statement to initialize two qubits. - Loops for
count
iterations. For each loop, it- Calls
SetQubitState
to set a specifiedinitial
value on the first qubit. - Calls
SetQubitState
again to set the second qubit to aZero
state. - Uses the
M
operation to measure each qubit. - Stores the number of measurements for each qubit that return
One
.
- Calls
- After the loop completes, it calls
SetQubitState
again to reset the qubits to a known state (Zero
) to allow others to allocate the qubits in a known state. This is required by theuse
statement. - Finally, it uses the
Message
function to display a message to the console before returning the results.
Test the code
Before moving on to the procedures for superposition and entanglement, test the code up to this point to see the initialization and measurement of the qubits.
To run the TestBellState
operation, you use the %simulate
magic command to call the Azure Quantum full-state simulator. You need to specify the count
and initial
arguments, for example, count=1000
and initial=1
. This initializes the first qubit to One
and measures each qubit 1000 times. Add a new cell with the following command and click Run all:
%simulate TestBellState count=1000 initial=1
and you should observe the following output:
q1:Zero, One q2:Zero, One
(0, 1000, 1000, 0)
Because the qubits haven't been manipulated yet, they have retained their initial values: the first qubit returns One
every time, and the second qubit returns Zero
.
If you run the cell again with initial=0
, you should observe that the first qubit also returns Zero
every time.
%simulate TestBellState count=1000 initial=0
q1:Zero, One q2:Zero, One
(1000, 0, 1000, 0)
Put a qubit in superposition
Currently, the qubits in the program are all in a classical state, that is, they are either 1 or 0. You know this because the program initializes the qubits to a known state, and you haven't added any processes to manipulate them. Before entangling the qubits, you will put the first qubit into a superposition state, where a measurement of the qubit will return Zero
50% of the time and One
50% of the time. Conceptually, the qubit can be thought of as being in a linear combination of all states between the Zero
and One
.
To put a qubit in superposition, Q# provides the H
, or Hadamard, operation. Recall the X
operation from the Initialize a qubit using measurement procedure earlier, which flipped a qubit from 0 to 1 (or vice versa); the H
operation flips the qubit halfway into a state of equal probabilities of 0 or 1. When measured, a qubit in superposition should return roughly an equal number of Zero
and One
results.
In the previous cell with the TestBellState
, add the H
operation inside the for
loop:
for test in 1..count {
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1); // Add the H operation after initialization and before measurement
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
Initialize the qubit to 1 again in the %simulate
command and click Run all, and you can see the results of the first qubit in superposition:
%simulate TestBellState count=1000 initial=1
q1:Zero, One q2:Zero, One
(523, 477, 1000, 0) // results will vary
Every time you run the program, the results for the first qubit will vary slightly, but will be close to 50% One
and 50% Zero
, while the results for the second qubit will remain Zero
all the time.
Q1:Zero/One Q2:Zero/One
(510, 490, 1000, 0)
Initializing the first qubit to Zero
returns similar results.
%simulate TestBellState count=1000 initial=0
Q1:Zero/One Q2:Zero/One
(504, 496, 1000, 0)
Entangle two qubits
As mentioned earlier, entangled qubits are connected such that they cannot be described independently from each other. That is, whatever operation happens to one qubit in an entangled pair, also happens to the other qubit. This allows you to know the resulting state of one qubit without measuring it, just by measuring the state of the other qubit. (This example uses two qubits; however, it is also possible to entangle three or more qubits).
To enable entanglement, Q# provides the CNOT
operation, which stands for Controlled-NOT. The result of running this operation on two qubits is to flip the second qubit if the first qubit is One
.
Add the CNOT
operation to the for
loop immediately after the H
operation. The TestBellState
operation should now look like this:
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1);
CNOT(q1, q2); // added CNOT operation
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones':
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Return number of |0> states, number of |1> states
Message("q1:Zero, One q2:Zero, One");
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
Click Run all to run the updated operation and you should see:
Q1:Zero/One Q2:Zero/One
(502, 498, 502, 498) // actual results will vary
The statistics for the first qubit haven't changed (a 50/50 chance of a Zero
or a One
after measurement), but the measurement results for the second qubit are always the same as the measurement of the first qubit, regardless of what the qubit is initialized to. The CNOT
operation has entangled the two qubits, so that whatever happens to one of them, happens to the other.
Prerequisites
- To run the code sample in the Copilot for Azure Quantum:
- A Microsoft (MSA) email account.
- For more information about the Copilot, see Explore Azure Quantum.
In this tutorial, you'll learn how to
- Create Q# operations to measure and initialize a qubit to a desired state.
- Create qubits and test your program.
- Put a qubit in superposition.
- Entangle a pair of qubits.
Initialize a qubit using measurement
The first step is to define a Q# operation that will initialize a qubit to a known state. This can be called to set a qubit to a classical state, meaning that, when measured, it either returns Zero
100% of the time or returns One
100% of the time. Measuring a qubit returns a type Result
, which can only have a value of Zero
or One
.
Note
Running a Q# program in the Copilot for Azure Quantum only requires the Q# code itself. Because the compiler is integrated into the Copilot, there is no need for a project file.
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
}
The code example introduces two standard operations, M
and X
, which transform the state of a qubit.
The SetQubitState
operation:
- Takes two parameters: a type
Result
, nameddesired
, that represents the desired state for the qubit to be in (Zero
orOne
), and a typeQubit
. - Performs a measurement operation,
M
, which measures the state of the qubit (Zero
orOne
) and compares the result to the value specified indesired
. - If the measurement does not match the compared value, it runs an
X
operation, which flips the state of the qubit to where the probabilities of a measurement returningZero
andOne
are reversed. This way,SetQubitState
always puts the target qubit in the desired state.
Test the measurement
Next, to demonstrate the effect of the SetQubitState
operation, create another operation named TestBellState
.
operation TestBellState() : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
let count = 1000;
let initial = One;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
The TestBellState
operation:
- Sets variables for the counter and the initial qubit state.
- Calls the
use
statement to initialize two qubits. - Loops for
count
iterations. For each loop, it- Calls
SetQubitState
to set a specifiedinitial
value on the first qubit. - Calls
SetQubitState
again to set the second qubit to aZero
state. - Uses the
M
operation to measure each qubit. - Stores the number of measurements for each qubit that return
One
.
- Calls
- After the loop completes, it calls
SetQubitState
again to reset the qubits to a known state (Zero
) to allow others to allocate the qubits in a known state. This is required by theuse
statement. - Finally, it uses the
Message
function to print results to the Copilot output windows before returning the results.
Test the code in the Copilot for Azure Quantum
Before moving on to the procedures for superposition and entanglement, you can test the code up to this point to see the initialization and measurement of the qubits.
In order to run the code as a standalone program, the Q# compiler in the Copilot needs to know where to start the program when you run the program. This is done in the Q# file by adding an @EntryPoint()
directly preceding the operation that you want to run first: the TestBellState
operation in this case.
Note
@EntryPoint()
is only required for standalone Q# programs. When running a Q# program in Jupyter Notebooks, or calling a Q# program from a Python or .NET host file, it is not required and will throw an error if included.
Add the @EntryPoint()
immediately before TestBellState
operation and your file up to this point should now look like this:
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
@EntryPoint()
operation TestBellState() : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
let count = 1000;
let initial = One;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
}
In the code, the count
and initial
variables are set to 1000
and One
respectively. This initializes the first qubit to One
and measures each qubit 1000 times.
Copy and paste the complete code sample into the Copilot for Azure Quantum code window, set the slide for the number of shots to "1", and click Run. The results are displayed in the histogram and in the Results fields.
Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0
Because the qubits haven't been manipulated yet, they have retained their initial values: the first qubit returns One
every time, and the second qubit returns Zero
.
If you change the value of initial
to Zero
and run the program again, you should observe that the first qubit also returns Zero
every time.
Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 0
Q2 - Ones: 1000
Put a qubit in superposition
Currently, the qubits in the program are all in a classical state, that is, they are either 1 or 0. You know this because the program initializes the qubits to a known state, and you haven't added any processes to manipulate them. Before entangling the qubits, you will put the first qubit into a superposition state, where a measurement of the qubit will return Zero
~50% of the time and One
~50% of the time. Conceptually, the qubit can be thought of as having an equal probability of measuring either Zero
or One
.
To put a qubit in superposition, Q# provides the H
, or Hadamard, operation. Recall the X
operation from the Initialize a qubit using measurement procedure earlier, which flipped a qubit from 0 to 1 (or vice versa); the H
operation flips the qubit halfway into a state of equal probabilities of Zero
or One
. When measured, a qubit in superposition should return roughly an equal number of Zero
and One
results.
Modify the code in the TestBellState
operation by resetting the initial value to One
and inserting a line for the H
operation:
for test in 1..count {
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1); // Add the H operation after initialization and before measurement
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
...
Now when you run the program, you can see the results of the first qubit in superposition:
Q1 - Zeros: 523 // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0
Every time you run the program, the results for the first qubit will vary slightly, but will be close to 50% One
and 50% Zero
, while the results for the second qubit will remain Zero
all the time.
Q1 - Zeros: 510
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0
Initializing the first qubit to Zero
returns similar results.
Q1 - Zeros: 504
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0
Note
By moving the slider in the Copilot for Azure Quantum and increasing the number of shots, you can see how the superposition results vary slightly over the distribution of the shots.
Entangle two qubits
As mentioned earlier, entangled qubits are connected such that they cannot be described independently from each other. That is, whatever operation happens to one qubit, also happens to the entangled qubit. This allows you to know the resulting state of one qubit without measuring it, just by measuring the state of the other qubit. (This example uses two qubits; however, it is also possible to entangle three or more qubits).
To enable entanglement, Q# provides the CNOT
operation, which stands for Controlled-NOT. The result of running this operation on two qubits is to flip the second qubit if the first qubit is One
.
Add the CNOT
operation to your program immediately after the H
operation. Your full program should look like this:
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
@EntryPoint()
operation TestBellState() : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
let count = 1000;
let initial = Zero;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1);
CNOT(q1, q2); // Add the CNOT operation after the H operation
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
}
Now when you run the program you should see something like
Q1 - Zeros: 502
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498
Notice that the statistics for the first qubit haven't changed (there is still a ~50/50 chance of a Zero
or a One
after measurement), but the measurement results for the second qubit are always the same as the measurement of the first qubit, no matter how many times you run the program. The CNOT
operation has entangled the two qubits, so that whatever happens to one of them, happens to the other.
Prerequisites
- To develop and run the code sample in your local development environment:
- Install the Quantum Development Kit (QDK) using your preferred language and development environment.
- If you already have the QDK installed, make sure you have updated to the latest version.
- Create a Q# project named Bell for either a Q# application or a C# host program. Alternatively, you can run your Q# code directly in Juptyer Notebooks or from a Python host program.
In this tutorial, you'll learn how to
- Create Q# operations to measure and initialize a qubit to a desired state.
- Create qubits and test your program.
- Put a qubit in superposition.
- Entangle a pair of qubits.
Initialize a qubit using measurement
The first step is to define a Q# operation that will initialize a qubit to a known state. This can be called to set a qubit to a classical state, meaning it either returns Zero
100% of the time or returns One
100% of the time. Zero
and One
are Q# values that represent the only two possible results of a measurement of a qubit.
In your project, replace the contents of Program.qs
with the following code:
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
}
The code example introduces two standard operations, M
and X
, which transform the state of a qubit.
The SetQubitState
operation:
- Takes two parameters: a type
Result
, nameddesired
, that represents the desired state for the qubit to be in (Zero
orOne
), and a typeQubit
. - Performs a measurement operation,
M
, which measures the state of the qubit (Zero
orOne
) and compares the result to the value specified indesired
. - If the measurement does not match the compared value, it runs an
X
operation, which flips the state of the qubit to where the probabilities of a measurement returningZero
andOne
are reversed. This way,SetQubitState
always puts the target qubit in the desired state.
Test the measurement
Next, to demonstrate the effect of the SetQubitState
operation, create another operation named TestBellState
.
Add the following operation to your Program.qs
file after the SetQubitState
operation:
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
The TestBellState
operation:
- Takes two parameters:
count
, the number of times to run a measurement, andinitial
, the desired state to initialize the qubit. - Calls the
use
statement to initialize two qubits. - Loops for
count
iterations. For each loop, it- Calls
SetQubitState
to set a specifiedinitial
value on the first qubit. - Calls
SetQubitState
again to set the second qubit to aZero
state. - Uses the
M
operation to measure each qubit. - Stores the number of measurements for each qubit that return
One
.
- Calls
- After the loop completes, it calls
SetQubitState
again to reset the qubits to a known state (Zero
) to allow others to allocate the qubits in a known state. This is required by theuse
statement. - Finally, it uses the
Message
function to print a message to the console before returning the results.
Run the code from the command prompt
Before moving on to the procedures for superposition and entanglement, test the code up to this point to see the initialization and measurement of the qubits.
In order to run the code as a standalone program, the Q# compiler needs to know where to start the program when you run the dotnet run
command. This is done in the Q# file by adding an @EntryPoint()
directly preceding the operation that you want to run: the TestBellState
operation in this case.
Note
@EntryPoint()
is only required for standalone Q# programs. When running a Q# program in Jupyter Notebooks, or calling a Q# program from a Python or .NET host file, it is not required and will throw an error if included.
Your program.qs
file should now look like this:
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
@EntryPoint()
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
}
To run the program, you need to specify the count
and initial
arguments from the command prompt. For example, --count 1000
and --initial One
will initialize the first qubit to One
and measure each qubit 1000 times. Run the following command:
dotnet run --count 1000 --initial One
and you should observe the following output:
Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0
Because the qubits haven't been manipulated yet, they have retained their initial values: the first qubit returns One
every time, and the second qubit returns Zero
.
If you run it with --initial Zero
, you should observe that the first qubit also returns Zero
every time.
dotnet run --count 1000 --initial Zero
Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 0
Q2 - Ones: 1000
Put a qubit in superposition
Currently, the qubits in the program are all in a classical state, that is, they are either 1 or 0. You know this because the program initializes the qubits to a known state, and you haven't added any processes to manipulate them. Before entangling the qubits, you will put the first qubit into a superposition state, where a measurement of the qubit will return Zero
50% of the time and One
50% of the time. Conceptually, the qubit can be thought of as halfway between the Zero
and One
.
To put a qubit in superposition, Q# provides the H
, or Hadamard, operation. Recall the X
operation from the Initialize a qubit using measurement procedure earlier, which flipped a qubit from Zero
to One
(or vice versa); the H
operation flips the qubit halfway into a state of equal probabilities of Zero
or One
. When measured, a qubit in superposition should return roughly an equal number of Zero
and One
results.
Modify the code in the TestBellState
operation to include the H
operation:
for test in 1..count {
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1); // Add the H operation after initialization and before measurement
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
...
Now when you run the program, you can see the results of the first qubit in superposition:
dotnet run --count 1000 --initial One
Q1 - Zeros: 523 // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0
Every time you run the program, the results for the first qubit will vary slightly, but will be close to 50% One
and 50% Zero
, while the results for the second qubit will remain Zero
all the time.
dotnet run --count 1000 --initial One
Q1 - Zeros: 510
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0
Initializing the first qubit to Zero
returns similar results.
dotnet run --count 1000 --initial Zero
Q1 - Zeros: 504
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0
Entangle two qubits
As mentioned earlier, entangled qubits are connected such that they cannot be described independently from each other. That is, whatever operation happens to one qubit, also happens to the entangled qubit. This allows you to know the resulting state of one qubit without measuring it, just by measuring the state of the other qubit. (This example uses two qubits; however, it is also possible to entangle three or more qubits).
To enable entanglement, Q# provides the CNOT
operation, which stands for Controlled-NOT. The result of running this operation on two qubits is to flip the second qubit if the first qubit is One
.
Add the CNOT
operation to your program immediately after the H
operation. Your full program should look like this:
namespace Bell {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
operation SetQubitState(desired : Result, target : Qubit) : Unit {
if desired != M(target) {
X(target);
}
}
@EntryPoint()
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
mutable numOnesQ1 = 0;
mutable numOnesQ2 = 0;
// allocate the qubits
use (q1, q2) = (Qubit(), Qubit());
for test in 1..count {
SetQubitState(initial, q1);
SetQubitState(Zero, q2);
H(q1);
CNOT(q1, q2); // Add the CNOT operation after the H operation
// measure each qubit
let resultQ1 = M(q1);
let resultQ2 = M(q2);
// Count the number of 'Ones' returned:
if resultQ1 == One {
set numOnesQ1 += 1;
}
if resultQ2 == One {
set numOnesQ2 += 1;
}
}
// reset the qubits
SetQubitState(Zero, q1);
SetQubitState(Zero, q2);
// Display the times that |0> is returned, and times that |1> is returned
Message($"Q1 - Zeros: {count - numOnesQ1}")
Message($"Q1 - Ones: {numOnesQ1}")
Message($"Q2 - Zeros: {count - numOnesQ2}")
Message($"Q2 - Ones: {numOnesQ2}")
return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
}
}
Now when you run the program:
dotnet run --count 1000 --initial One
Q1 - Zeros: 502
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498
The statistics for the first qubit haven't changed (a 50/50 chance of a Zero
or a One
after measurement), but the measurement results for the second qubit are always the same as the measurement of the first qubit. The CNOT
operation has entangled the two qubits, so that whatever happens to one of them, happens to the other.
Next steps
Continue to explore other quantum algorithms and techniques:
- The tutorial Implement Grover’s search algorithm shows how to write a Q# program that uses Grover's search algorithm to solve a graph coloring problem.
- The tutorial Write and simulate qubit-level programs in Q# explores how to write a Q# program that directly addresses specific qubits.
- The Quantum Katas are Jupyter Notebook-based, self-paced tutorials and programming exercises aimed at teaching the elements of quantum computing and Q# programming at the same time.
Feedback
Submit and view feedback for