Start phase estimation kata (#61)
This kata contains a section on quantum phase estimation and a start of a section on iterative phase estimation. Iterative PE is a large topic and will require more tasks to cover adequately, but I wanted to share at least the beginnings of this kata.
This commit is contained in:
Родитель
e6dfc19ea3
Коммит
3895fd6b45
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"quantum.quantum-devkit-vscode"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build"
|
||||
],
|
||||
"type": "process",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"test"
|
||||
],
|
||||
"type": "process",
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains parts of the testing harness.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Quantum.Simulation.Core;
|
||||
using Microsoft.Quantum.Simulation.Simulators;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Quantum.Kata.PhaseEstimation
|
||||
{
|
||||
/// <summary>
|
||||
/// This custom quantum simulator keeps track of the number of times
|
||||
/// each operation is executed, by providing a custom native operation:
|
||||
/// `AssertOracleCallsCount` which asserts the number of times
|
||||
/// the given oracle (operation) has been called.
|
||||
/// </summary>
|
||||
public class CounterSimulator : QuantumSimulator
|
||||
{
|
||||
private Dictionary<ICallable, int> _operationsCount = new Dictionary<ICallable, int>();
|
||||
private static long _qubitsAllocated = 0;
|
||||
private static long _maxQubitsAllocated = 0;
|
||||
|
||||
#region Counting operations
|
||||
public CounterSimulator(
|
||||
bool throwOnReleasingQubitsNotInZeroState = true,
|
||||
uint? randomNumberGeneratorSeed = null,
|
||||
bool disableBorrowing = false) :
|
||||
base(throwOnReleasingQubitsNotInZeroState, randomNumberGeneratorSeed, disableBorrowing)
|
||||
{
|
||||
this.OnOperationStart += CountOperationCalls;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method for the OnOperationStart event.
|
||||
/// </summary>
|
||||
public void CountOperationCalls(ICallable op, IApplyData data)
|
||||
{
|
||||
if (_operationsCount.ContainsKey(op))
|
||||
{
|
||||
_operationsCount[op]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_operationsCount[op] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Native operation to reset the oracle counts back to 0.
|
||||
public class ResetOracleCallsImpl : ResetOracleCallsCount
|
||||
{
|
||||
CounterSimulator _sim;
|
||||
|
||||
public ResetOracleCallsImpl(CounterSimulator m) : base(m)
|
||||
{
|
||||
_sim = m;
|
||||
}
|
||||
|
||||
public override Func<QVoid, QVoid> Body => (__in) =>
|
||||
{
|
||||
_sim._operationsCount.Clear();
|
||||
return QVoid.Instance;
|
||||
};
|
||||
}
|
||||
|
||||
public class GetOracleCallsImpl<T> : GetOracleCallsCount<T>
|
||||
{
|
||||
CounterSimulator _sim;
|
||||
|
||||
public GetOracleCallsImpl(CounterSimulator m) : base(m)
|
||||
{
|
||||
_sim = m;
|
||||
}
|
||||
|
||||
public override Func<T, long> Body => (__in) =>
|
||||
{
|
||||
var oracle = __in;
|
||||
|
||||
var op = oracle as ICallable;
|
||||
Assert.NotNull(op);
|
||||
|
||||
var actual = _sim._operationsCount.ContainsKey(op) ? _sim._operationsCount[op] : 0;
|
||||
|
||||
return actual;
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Counting allocated qubits
|
||||
new public class Allocate : Microsoft.Quantum.Simulation.Simulators.SimulatorBase.Allocate
|
||||
{
|
||||
public Allocate(SimulatorBase m) : base(m) { }
|
||||
|
||||
public override Qubit Apply()
|
||||
{
|
||||
_qubitsAllocated++;
|
||||
if (_qubitsAllocated > _maxQubitsAllocated)
|
||||
{
|
||||
_maxQubitsAllocated = _qubitsAllocated;
|
||||
}
|
||||
return base.Apply();
|
||||
}
|
||||
|
||||
public override QArray<Qubit> Apply(long count)
|
||||
{
|
||||
_qubitsAllocated += count;
|
||||
if (_qubitsAllocated > _maxQubitsAllocated)
|
||||
{
|
||||
_maxQubitsAllocated = _qubitsAllocated;
|
||||
}
|
||||
return base.Apply(count);
|
||||
}
|
||||
}
|
||||
|
||||
new public class Release : Microsoft.Quantum.Simulation.Simulators.SimulatorBase.Release
|
||||
{
|
||||
public Release(SimulatorBase m) : base(m) { }
|
||||
|
||||
public override void Apply(Qubit q)
|
||||
{
|
||||
_qubitsAllocated--;
|
||||
base.Apply(q);
|
||||
}
|
||||
|
||||
public override void Apply(QArray<Qubit> qubits)
|
||||
{
|
||||
_qubitsAllocated -= qubits.Length;
|
||||
base.Apply(qubits);
|
||||
}
|
||||
}
|
||||
|
||||
public class ResetQubitCountImpl : ResetQubitCount
|
||||
{
|
||||
|
||||
public ResetQubitCountImpl(CounterSimulator m) : base(m) { }
|
||||
|
||||
public override Func<QVoid, QVoid> Body => (__in) =>
|
||||
{
|
||||
_qubitsAllocated = 0;
|
||||
_maxQubitsAllocated = 0;
|
||||
return QVoid.Instance;
|
||||
};
|
||||
}
|
||||
|
||||
public class GetMaxQubitCountImpl : GetMaxQubitCount
|
||||
{
|
||||
public GetMaxQubitCountImpl(CounterSimulator m) : base(m) { }
|
||||
|
||||
public override Func<QVoid, long> Body => (__in) =>
|
||||
{
|
||||
return _maxQubitsAllocated;
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>Quantum.Kata.PhaseEstimation</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.4.1901.3104" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.4.1901.3104" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.4.1901.3104" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2036
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PhaseEstimation", "PhaseEstimation.csproj", "{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7CB0806C-1BBF-4E0C-BDFC-04A9A068F41C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,28 @@
|
|||
# Welcome!
|
||||
|
||||
This kata covers phase estimation algorithms, which are some of the most fundamental building blocks of quantum algorithms.
|
||||
|
||||
Phase estimation is the task of estimating the eigenvalue of an eigenvector of a unitary operator. Since the absolute value of the eigenvalue is always 1, the eigenvalue can be represented as exp(2iπφ), and phase estimation algorithms are usually formulated in terms of estimating the phase φ.
|
||||
|
||||
#### Theory
|
||||
|
||||
Eigenvalues and eigenvectors:
|
||||
|
||||
* [Wikipedia article](https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors).
|
||||
|
||||
Quantum phase estimation:
|
||||
|
||||
* Wikipedia article on [quantum phase estimation](https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm).
|
||||
* Lectures [8](https://cs.uwaterloo.ca/~watrous/LectureNotes/CPSC519.Winter2006/08.pdf) and [9](https://cs.uwaterloo.ca/~watrous/LectureNotes/CPSC519.Winter2006/09.pdf) by John Watrous.
|
||||
* [Quantum Phase Estimation](https://docs.microsoft.com/en-us/quantum/libraries/standard/algorithms) in Q# documentation.
|
||||
|
||||
Iterative phase estimation:
|
||||
|
||||
* [Faster Phase Estimation](https://arxiv.org/pdf/1304.0741.pdf) paper gives an overview of several different approaches.
|
||||
* [Iterative Phase Estimation](https://docs.microsoft.com/en-us/quantum/libraries/standard/characterization) in Q# documentation.
|
||||
|
||||
#### Q# materials
|
||||
|
||||
* [Quantum phase estimation tests](https://github.com/Microsoft/QuantumLibraries/blob/master/Canon/tests/QuantumPhaseEstimationTests.qs)
|
||||
* [Bayesian (iterative) phase estimation sample](https://github.com/Microsoft/Quantum/blob/master/Samples/src/PhaseEstimation/BayesianPhaseEstimation.qs)
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains reference solutions to all tasks.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
// We recommend that you try to solve the tasks yourself first,
|
||||
// but feel free to look up the solution if you get stuck.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Quantum phase estimation (QPE)
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. Inputs to QPE: eigenstates of Z/S/T gates.
|
||||
operation Eigenstates_ZST_Reference (q : Qubit, state : Int) : Unit {
|
||||
|
||||
body (...) {
|
||||
if (state == 1) {
|
||||
X(q);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation UnitaryPowerImpl_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int, q : Qubit) : Unit {
|
||||
body (...) {
|
||||
for (i in 1..power) {
|
||||
U(q);
|
||||
}
|
||||
}
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
// Task 1.2. Inputs to QPE: powers of Z/S/T gates.
|
||||
function UnitaryPower_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int) : (Qubit => Unit : Adjoint, Controlled) {
|
||||
return UnitaryPowerImpl_Reference(U, power, _);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Task 1.3. Validate inputs to QPE
|
||||
operation AssertIsEigenstate_Reference (U : (Qubit => Unit), P : (Qubit => Unit : Adjoint)) : Unit {
|
||||
using (q = Qubit()) {
|
||||
// Prepare the state |ψ⟩
|
||||
P(q);
|
||||
// Apply the given unitary
|
||||
U(q);
|
||||
// If the given state is an eigenstate, the current state of the qubit should be |ψ⟩ (up to a global phase).
|
||||
// So un-preparing it should bring the state back to |0⟩
|
||||
Adjoint P(q);
|
||||
AssertQubit(Zero, q);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation Oracle_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int, target : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
for (i in 1 .. power) {
|
||||
U(target[0]);
|
||||
}
|
||||
}
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
// Task 1.4. QPE for single-qubit unitaries
|
||||
operation QPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), n : Int) : Double {
|
||||
// Construct a phase estimation oracle from the unitary
|
||||
let oracle = DiscreteOracle(Oracle_Reference(U, _, _));
|
||||
mutable phase = -1.0;
|
||||
// Allocate qubits to hold the eigenstate of U and the phase in a big endian register
|
||||
using ((eigenstate, phaseRegister) = (Qubit[1], Qubit[n])) {
|
||||
let phaseRegisterBE = BigEndian(phaseRegister);
|
||||
// Prepare the eigenstate of U
|
||||
P(eigenstate[0]);
|
||||
// Call library
|
||||
QuantumPhaseEstimation(oracle, eigenstate, phaseRegisterBE);
|
||||
// Read out the phase
|
||||
set phase = ToDouble(MeasureIntegerBE(phaseRegisterBE)) / ToDouble(1 <<< n);
|
||||
|
||||
ResetAll(eigenstate);
|
||||
ResetAll(phaseRegister);
|
||||
}
|
||||
|
||||
return phase;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Iterative phase estimation
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. Single-bit phase estimation
|
||||
operation SingleBitPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Int {
|
||||
mutable eigenvalue = 0;
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
H(control);
|
||||
|
||||
set eigenvalue = M(control) == Zero ? 1 | -1;
|
||||
|
||||
ResetAll([control, eigenstate]);
|
||||
}
|
||||
return eigenvalue;
|
||||
}
|
||||
|
||||
|
||||
// Task 2.2. Two bit phase estimation
|
||||
operation TwoBitPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Double {
|
||||
// Start by using the same circuit as in task 2.1.
|
||||
// For eigenvalues +1 and -1, it produces measurement results Zero and One, respectively, 100% of the time;
|
||||
// for eigenvalues +i and -i, it produces both results with 50% probability, so a different circuit is required.
|
||||
mutable (nZero, nOne) = (0, 0);
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
mutable iter = 0;
|
||||
repeat {
|
||||
set iter = iter + 1;
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
H(control);
|
||||
|
||||
if (MResetZ(control) == Zero) {
|
||||
set nZero = nZero + 1;
|
||||
} else {
|
||||
set nOne = nOne + 1;
|
||||
}
|
||||
|
||||
// repeat the loop until we get both Zero and One measurement outcomes
|
||||
// or until we're reasonably certain that we won't get a different outcome
|
||||
} until (iter == 10 || nZero > 0 && nOne > 0)
|
||||
fixup {}
|
||||
|
||||
Reset(eigenstate);
|
||||
}
|
||||
|
||||
if (nOne == 0) {
|
||||
// all measurements yielded Zero => eigenvalue +1
|
||||
return 0.0;
|
||||
}
|
||||
if (nZero == 0) {
|
||||
// all measurements yielded One => eigenvalue -1
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
// To distinguish between eigenvalues i and -i, we need a circuit with an extra S gate on control qubit
|
||||
mutable eigenvalue = -1.0;
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
S(control);
|
||||
H(control);
|
||||
|
||||
set eigenvalue = MResetZ(control) == Zero ? 0.75 | 0.25;
|
||||
|
||||
Reset(eigenstate);
|
||||
}
|
||||
return eigenvalue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Diagnostics;
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Welcome!
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// The "Phase estimation" quantum kata is a series of exercises designed
|
||||
// to teach you the basics of phase estimation algorithms.
|
||||
// It covers the following topics:
|
||||
// - quantum phase estimation,
|
||||
// - iterative phase estimation,
|
||||
// - preparing necessary inputs to phase estimation routines and applying them.
|
||||
|
||||
// Each task is wrapped in one operation preceded by the description of the task.
|
||||
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
|
||||
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
|
||||
// with some Q# code to make the failing test pass.
|
||||
|
||||
// Within each section, tasks are given in approximate order of increasing difficulty;
|
||||
// harder ones are marked with asterisks.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Quantum phase estimation (QPE)
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. Inputs to QPE: eigenstates of Z/S/T gates.
|
||||
// Inputs:
|
||||
// 1) a qubit in |0⟩ state.
|
||||
// 2) an integer indicating which eigenstate to prepare.
|
||||
// Goal:
|
||||
// Prepare one of the eigenstates of Z gate (which are the same as eigenstates of S or T gates):
|
||||
// eigenstate |0⟩ if state = 0, or eigenstate |1⟩ if state = 1.
|
||||
operation Eigenstates_ZST (q : Qubit, state : Int) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.2. Inputs to QPE: powers of Z/S/T gates.
|
||||
// Inputs:
|
||||
// 1) a single-qubit unitary U.
|
||||
// 2) a positive integer power.
|
||||
// Output:
|
||||
// A single-qubit unitary equal to U raised to the given power.
|
||||
function UnitaryPower (U : (Qubit => Unit : Adjoint, Controlled), power : Int) : (Qubit => Unit : Adjoint, Controlled) {
|
||||
// Hint: Remember that you can define auxiliary operations.
|
||||
|
||||
// ...
|
||||
|
||||
// Currently this function returns the input unitary for the sake of being able to compile the code.
|
||||
// You will need to return your own unitary instead of U.
|
||||
return U;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.3. Validate inputs to QPE
|
||||
// Inputs:
|
||||
// 1) a single-qubit unitary U.
|
||||
// 2) a single-qubit state |ψ⟩ represented by a unitary P such that |ψ⟩ = P|0⟩
|
||||
// (i.e., applying the unitary P to state |0⟩ prepares state |ψ⟩).
|
||||
// Goal:
|
||||
// Assert that the given state is an eigenstate of the given unitary,
|
||||
// i.e., do nothing if it is, and throw an exception if it is not.
|
||||
operation AssertIsEigenstate (U : (Qubit => Unit), P : (Qubit => Unit : Adjoint)) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 1.4. QPE for single-qubit unitaries
|
||||
// Inputs:
|
||||
// 1) a single-qubit unitary U.
|
||||
// 2) a single-qubit eigenstate of U |ψ⟩ represented by a unitary P such that |ψ⟩ = P|0⟩
|
||||
// (i.e., applying the unitary P to state |0⟩ prepares state |ψ⟩).
|
||||
// 3) an integer n.
|
||||
// Output:
|
||||
// The phase of the eigenvalue that corresponds to the eigenstate |ψ⟩, with n bits of precision.
|
||||
// The phase should be between 0 and 1.
|
||||
operation QPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), n : Int) : Double {
|
||||
// ...
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.5. Test your QPE implementation
|
||||
// Goal: Use your QPE implementation from task 1.4 to run quantum phase estimation
|
||||
// on several simple unitaries and their eigenstates.
|
||||
// This task is not covered by a test and allows you to experiment with running the algorithm.
|
||||
operation T15_E2E_QPE_Test () : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Iterative phase estimation
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Unlike quantum phase estimation, which is a single algorithm,
|
||||
// iterative phase estimation is a whole class of algorithms based on the same idea:
|
||||
// treating phase estimation as a classical algorithm which learns the phase via a sequence of measurements
|
||||
// (the measurement performed on each iteration can depend on the outcomes of previous iterations).
|
||||
|
||||
// A typical circuit for one iteration has the following structure:
|
||||
//
|
||||
// ┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
// control: |0>─┤ H ├──┤ R ├───┬───┤ H ├──┤ M ╞══
|
||||
// └───┘ └───┘┌──┴──┐└───┘ └───┘
|
||||
// eigenstate: |ψ>─────────────┤ Uᴹ ├──────────────
|
||||
// └─────┘
|
||||
//
|
||||
// (R is a rotation gate, and M is a power of the unitary U;
|
||||
// both depend on the current information about the phase).
|
||||
//
|
||||
// The result of the measurement performed on the top qubit defines the next iteration.
|
||||
|
||||
|
||||
// Task 2.1. Single-bit phase estimation
|
||||
// Inputs:
|
||||
// 1) a single-qubit unitary U that is guaranteed to have an eigenvalue +1 or -1
|
||||
// (with eigenphases 0.0 or 0.5, respectively).
|
||||
// 2) a single-qubit eigenstate of U |ψ⟩ represented by a unitary P such that |ψ⟩ = P|0⟩
|
||||
// (i.e., applying the unitary P to state |0⟩ prepares state |ψ⟩).
|
||||
// Output:
|
||||
// The eigenvalue which corresponds to the eigenstate |ψ⟩ (+1 or -1).
|
||||
//
|
||||
// You are allowed to allocate exactly two qubits and call Controlled U exactly once.
|
||||
operation SingleBitPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Int {
|
||||
// Note: It is possible to use the QPE implementation from task 1.4 to solve this task,
|
||||
// but we suggest you implement the circuit by hand for the sake of learning.
|
||||
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Task 2.2. Two bit phase estimation
|
||||
// Inputs:
|
||||
// 1) a single-qubit unitary U that is guaranteed to have an eigenvalue +1, i, -1 or -i
|
||||
// (with eigenphases 0.0, 0.25, 0.5 or 0.75, respectively).
|
||||
// 2) a single-qubit eigenstate of U |ψ⟩ represented by a unitary P such that |ψ⟩ = P|0⟩
|
||||
// (i.e., applying the unitary P to state |0⟩ prepares state |ψ⟩).
|
||||
// Output:
|
||||
// The eigenphase which corresponds to the eigenstate |ψ⟩ (0.0, 0.25, 0.5 or 0.75).
|
||||
// The returned value has to be accurate within the absolute error of 0.001.
|
||||
//
|
||||
// You are allowed to allocate exactly two qubits and call Controlled U multiple times.
|
||||
operation TwoBitPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Double {
|
||||
// Hint: Start by applying the same circuit as in task 2.1.
|
||||
// What are the possible outcomes for each eigenvalue?
|
||||
// What eigenvalues you can and can not distinguish using this circuit?
|
||||
|
||||
// ...
|
||||
|
||||
// Hint 2: What eigenvalues you can and can not distinguish using this circuit?
|
||||
// What circuit you can apply to distinguish them?
|
||||
|
||||
// ...
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
|
||||
// To be continued...
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains parts of the testing harness.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
using Microsoft.Quantum.Simulation.XUnit;
|
||||
using System.Diagnostics;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Quantum.Kata.PhaseEstimation
|
||||
{
|
||||
public class TestSuiteRunner
|
||||
{
|
||||
private readonly ITestOutputHelper output;
|
||||
|
||||
public TestSuiteRunner(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This driver will run all Q# tests (operations named "...Test")
|
||||
/// that belong to namespace Quantum.Kata.PhaseEstimation.
|
||||
/// </summary>
|
||||
[OperationDriver(TestNamespace = "Quantum.Kata.PhaseEstimation")]
|
||||
public void TestTarget(TestOperation op)
|
||||
{
|
||||
using (var sim = new CounterSimulator())
|
||||
{
|
||||
// OnLog defines action(s) performed when Q# test calls function Message
|
||||
sim.OnLog += (msg) => { output.WriteLine(msg); };
|
||||
sim.OnLog += (msg) => { Debug.WriteLine(msg); };
|
||||
op.TestOperationRunner(sim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains parts of the testing harness.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
using Microsoft.Quantum.Primitive;
|
||||
using Microsoft.Quantum.Simulation.Core;
|
||||
using Microsoft.Quantum.Simulation.Simulators;
|
||||
using Quantum.Kata.PhaseEstimation;
|
||||
using System.Diagnostics;
|
||||
using Xunit;
|
||||
|
||||
namespace T13
|
||||
{
|
||||
public class EigenstateAssertion
|
||||
{
|
||||
void TestFailingAssertOnUnitaries(QuantumSimulator sim, ICallable unitary, IAdjointable prep)
|
||||
{
|
||||
bool exceptionThrown = false;
|
||||
try
|
||||
{
|
||||
AssertIsEigenstate.Run(sim, unitary, prep).Wait();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
exceptionThrown = true;
|
||||
System.Console.WriteLine(e);
|
||||
}
|
||||
Xunit.Assert.True(exceptionThrown, "An exception should have been thrown if the state was not an eigenstate");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void T13_AssertIsEigenstate_Test()
|
||||
{
|
||||
using (var sim = new CounterSimulator())
|
||||
{
|
||||
sim.OnLog += (msg) => { Debug.WriteLine(msg); };
|
||||
|
||||
// First, test state/unitary pairs which are eigenstates.
|
||||
// Neither pair should throw an exception, so we can test them all together.
|
||||
try
|
||||
{
|
||||
TestAssertIsEigenstate_True.Run(sim).Wait();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
System.Console.WriteLine(e);
|
||||
Xunit.Assert.False(true, "An exception should not have been thrown if the state was an eigenstate");
|
||||
}
|
||||
|
||||
// Second, test pairs which are not eigenstates.
|
||||
// Since each pair has to throw an exception, each pair has to be tested separately.
|
||||
var Xgate = sim.Get<IAdjointable, X>();
|
||||
var Ygate = sim.Get<IAdjointable, Y>();
|
||||
var Zgate = sim.Get<IAdjointable, Z>();
|
||||
var Hgate = sim.Get<IAdjointable, H>();
|
||||
TestFailingAssertOnUnitaries(sim, Zgate, Hgate);
|
||||
TestFailingAssertOnUnitaries(sim, Xgate, Xgate);
|
||||
TestFailingAssertOnUnitaries(sim, Xgate, Zgate);
|
||||
TestFailingAssertOnUnitaries(sim, Ygate, Hgate);
|
||||
TestFailingAssertOnUnitaries(sim, Ygate, Xgate);
|
||||
TestFailingAssertOnUnitaries(sim, Ygate, Zgate);
|
||||
TestFailingAssertOnUnitaries(sim, Hgate, Xgate);
|
||||
TestFailingAssertOnUnitaries(sim, Hgate, Zgate);
|
||||
TestFailingAssertOnUnitaries(sim, Hgate, Hgate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains testing harness for all tasks.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Quantum phase estimation (QPE)
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation AssertEqualOnZeroState1 (testImpl : (Qubit => Unit), refImpl : (Qubit => Unit : Adjoint)) : Unit {
|
||||
using (q = Qubit()) {
|
||||
// apply operation that needs to be tested
|
||||
testImpl(q);
|
||||
|
||||
// apply adjoint reference operation and check that the result is |0⟩
|
||||
Adjoint refImpl(q);
|
||||
|
||||
AssertQubit(Zero, q);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
operation T11_Eigenstates_ZST_Test () : Unit {
|
||||
for (state in 0..1) {
|
||||
AssertEqualOnZeroState1(Eigenstates_ZST(_, state), Eigenstates_ZST_Reference(_, state));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to represent operation on one qubit as an operation on an array of qubits
|
||||
operation ArrayWrapperOperation1 (op : (Qubit => Unit : Adjoint, Controlled), qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
operation T12_UnitaryPower_Test () : Unit {
|
||||
for (U in [Z, S, T]) {
|
||||
for (power in 1..5) {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation1(UnitaryPower(U, power), _),
|
||||
ArrayWrapperOperation1(UnitaryPower_Reference(U, power), _), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation TestAssertIsEigenstate_True () : Unit {
|
||||
// Test state/unitary pairs which are eigenstates (so no exception should be thrown)
|
||||
for ((unitary, statePrep) in [(Z, I), (Z, X),
|
||||
(S, I), (S, X),
|
||||
(X, H), (X, BindCA([X, H])),
|
||||
(Y, BindCA([H, S])), (Y, BindCA([X, H, S]))]) {
|
||||
AssertIsEigenstate(unitary, statePrep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T14_QPE_Test () : Unit {
|
||||
AssertAlmostEqualTol(QPE(Z, I, 1), 0.0, 0.25);
|
||||
AssertAlmostEqualTol(QPE(Z, X, 1), 0.5, 0.25);
|
||||
|
||||
AssertAlmostEqualTol(QPE(S, I, 2), 0.0, 0.125);
|
||||
AssertAlmostEqualTol(QPE(S, X, 2), 0.25, 0.125);
|
||||
|
||||
AssertAlmostEqualTol(QPE(T, I, 3), 0.0, 0.0625);
|
||||
AssertAlmostEqualTol(QPE(T, X, 3), 0.125, 0.0625);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Iterative phase estimation
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation Test1BitPEOnOnePair(U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), expected : Int) : Unit {
|
||||
ResetQubitCount();
|
||||
ResetOracleCallsCount();
|
||||
|
||||
let actual = SingleBitPE(U, P);
|
||||
AssertIntEqual(actual, expected, $"Unexpected return for ({U}, {P}): expected {expected}, got {actual}");
|
||||
|
||||
let nq = GetMaxQubitCount();
|
||||
AssertIntEqual(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
|
||||
let nu = GetOracleCallsCount(Controlled U);
|
||||
AssertIntEqual(nu, 1, $"You are allowed to call Controlled U exactly once, and you called it {nu} times");
|
||||
}
|
||||
|
||||
operation T21_SingleBitPE_Test () : Unit {
|
||||
Test1BitPEOnOnePair(Z, I, +1);
|
||||
Test1BitPEOnOnePair(Z, X, -1);
|
||||
Test1BitPEOnOnePair(X, H, +1);
|
||||
Test1BitPEOnOnePair(X, BindCA([X, H]), -1);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation Test2BitPEOnOnePair(U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), expected : Double) : Unit {
|
||||
ResetQubitCount();
|
||||
|
||||
let actual = TwoBitPE(U, P);
|
||||
AssertAlmostEqualTol(actual, expected, 0.001);
|
||||
|
||||
let nq = GetMaxQubitCount();
|
||||
AssertIntEqual(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
}
|
||||
|
||||
operation T22_TwoBitPE_Test () : Unit {
|
||||
Test2BitPEOnOnePair(Z, I, 0.0);
|
||||
Test2BitPEOnOnePair(Z, X, 0.5);
|
||||
Test2BitPEOnOnePair(S, X, 0.25);
|
||||
Test2BitPEOnOnePair(BindCA([S, Z]), X, 0.75);
|
||||
|
||||
Test2BitPEOnOnePair(X, H, 0.0);
|
||||
Test2BitPEOnOnePair(X, BindCA([X, H]), 0.5);
|
||||
Test2BitPEOnOnePair(BindCA([H, S, H]), H, 0.0);
|
||||
Test2BitPEOnOnePair(BindCA([H, S, H]), BindCA([X, H]), 0.25);
|
||||
Test2BitPEOnOnePair(BindCA([H, S, Z, H]), BindCA([X, H]), 0.75);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
function GetOracleCallsCount<'T> (oracle : 'T) : Int { return 0; }
|
||||
|
||||
function ResetOracleCallsCount () : Unit { }
|
||||
|
||||
function GetMaxQubitCount () : Int { return 0; }
|
||||
|
||||
function ResetQubitCount () : Unit { }
|
||||
}
|
|
@ -25,6 +25,10 @@
|
|||
{
|
||||
"path": "Measurements"
|
||||
},
|
||||
{
|
||||
"path": "PhaseEstimation",
|
||||
"name": "Phase Estimation"
|
||||
},
|
||||
{
|
||||
"path": "QEC_BitFlipCode",
|
||||
"name": "QEC: Bit-flip Code"
|
||||
|
|
|
@ -23,6 +23,8 @@ Currently covered topics are:
|
|||
This kata introduces Simon's algorithm.
|
||||
* **[Grover's algorithm](./GroversAlgorithm/)**.
|
||||
This kata introduces Grover's search algorithm and writing quantum oracles to be used with it.
|
||||
* **[Phase estimation](./PhaseEstimation/)**.
|
||||
This kata covers phase estimation algorithms.
|
||||
* **[Bit-flip error correcting code](./QEC_BitFlipCode/)**.
|
||||
This kata introduces a 3-qubit error correcting code for protecting against bit-flip errors.
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче