* Release 0.3.1810

* Update Canon/src/AmplitudeAmplification/Utils.qs

Co-Authored-By: anpaz-msft <anpaz@microsoft.com>

* Update Canon/src/Combinators/RestrictToSubregister.qs

Co-Authored-By: anpaz-msft <anpaz@microsoft.com>

* Update Canon/src/AmplitudeAmplification/AmplitudeAmplification.qs

Co-Authored-By: anpaz-msft <anpaz@microsoft.com>

* Update Canon/src/Arithmetic/Arithmetic.qs

Co-Authored-By: anpaz-msft <anpaz@microsoft.com>
This commit is contained in:
Andres Paz 2018-10-25 18:28:58 -07:00 коммит произвёл Martin Roetteler
Родитель e8743d675f
Коммит 038ddfd42e
349 изменённых файлов: 17504 добавлений и 23813 удалений

53
.gitattributes поставляемый
Просмотреть файл

@ -7,4 +7,55 @@
###############################################################################
# diff behavior for some non-binary formats
###############################################################################
*.md diff=text
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
*.md diff=astextplain
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

4
.gitignore поставляемый
Просмотреть файл

@ -15,10 +15,6 @@ packages/
*.exe
*.chm
# These files are generated by bootstrap from a .v.template (version template).
# Any changes must be done to the corresponding the .v.template file directly
Microsoft.Quantum.Canon/Microsoft.Quantum.Canon.nuspec
# Python interop build outputs:
Interoperability/python/build
Interoperability/python/dist

Просмотреть файл

@ -1,29 +0,0 @@
language: csharp
dotnet: 2.1.301
mono: none
matrix:
include:
- os: osx
# The default image for Linux provided by Travis CI uses GCC 4.8,
# but since GCC also includes the GNU implementation of OpenMP,
# we need to update GCC to get the version of OpenMP that the
# Quantum Development Kit was built against. To do so, we add
# the APT source provided by Travis CI for more recent versions
# of GCC backported to Ubuntu 14.04 Trusty.
- os: linux
env:
- OMP_NUM_THREADS=1
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
script:
- dotnet build QsharpLibraries.sln
- dotnet test Samples/UnitTesting
- travis_wait 30 dotnet test LibraryTests
- dotnet test Samples/OpenQasmReader.Tests

Просмотреть файл

@ -9,8 +9,10 @@ steps:
- task: DotNetCoreCLI@2
displayName: 'Build Libraries'
inputs:
projects: '**/*.sln'
arguments: '-c $(BuildConfiguration) -v n'
projects: |
$(LibrariesRootFolder)/Canon.sln
$(LibrariesRootFolder)/Chemistry.sln
arguments: '-c $(BuildConfiguration) -v n /p:Version=$(Assembly.Version)'
##
@ -21,7 +23,22 @@ steps:
inputs:
command: test
projects: |
Samples/UnitTesting
LibraryTests
arguments: '-c $(BuildConfiguration) -v n'
$(LibrariesRootFolder)/Canon/tests
$(LibrariesRootFolder)/Chemistry/tests/ChemistryTests/ChemistryTests.csproj
$(LibrariesRootFolder)/Chemistry/tests/SystemTests/SystemTests.csproj
$(LibrariesRootFolder)/Chemistry/tests/DataModelTests/DataModelTests.csproj
arguments: '-c $(BuildConfiguration) -v n /p:Version=$(Assembly.Version)'
##
# Create Nuget.
##
- task: DotNetCoreCLI@2
displayName: 'Pack Libraries nugets'
inputs:
command: custom
custom: pack
projects: |
$(LibrariesRootFolder)/Canon/src/Canon.csproj
$(LibrariesRootFolder)/Chemistry/src/DataModel/DataModel.csproj
arguments: ' --no-build -c $(BuildConfiguration) -v n -o $(System.DefaultWorkingDirectory) /p:PackageVersion=$(Nuget.Version)'

Просмотреть файл

@ -0,0 +1,34 @@
##
# Builds and creates the Q# Python interop package.
##
steps:
- task: NuGetToolInstaller@0
displayName: 'Use NuGet 4.3.0'
- task: CondaEnvironment@1
displayName: 'Create and update conda environment'
inputs:
environmentName: qsharp-build
packageSpecs: 'python=3 conda-build=3.15.1'
- task: PowerShell@1
displayName: 'Python Interop conda build 3.5'
inputs:
scriptName: '$(LibrariesRootFolder)/Interoperability/python/build.ps1'
arguments: '-PythonVersion 3.5'
workingFolder: '$(LibrariesRootFolder)/Interoperability/python'
failOnStandardError: false
condition: and(succeeded(), variables['Python3.5'])
- task: PowerShell@1
displayName: 'Python Interop conda build 3.6'
inputs:
scriptName: '$(LibrariesRootFolder)/Interoperability/python/build.ps1'
arguments: '-PythonVersion 3.6'
workingFolder: '$(LibrariesRootFolder)/Interoperability/python'
failOnStandardError: false

42
Canon.sln Normal file
Просмотреть файл

@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{561759D2-4D2D-4EE3-9565-9AAEC4A7D64B}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canon", "Canon\src\Canon.csproj", "{A36EEB3F-89F0-4435-8527-2E68CC6067E1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canon.Tests", "Canon\tests\Canon.Tests.csproj", "{DEDA9681-2C11-492F-B1C9-D772BB45730A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A36EEB3F-89F0-4435-8527-2E68CC6067E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A36EEB3F-89F0-4435-8527-2E68CC6067E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A36EEB3F-89F0-4435-8527-2E68CC6067E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A36EEB3F-89F0-4435-8527-2E68CC6067E1}.Release|Any CPU.Build.0 = Release|Any CPU
{DEDA9681-2C11-492F-B1C9-D772BB45730A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEDA9681-2C11-492F-B1C9-D772BB45730A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEDA9681-2C11-492F-B1C9-D772BB45730A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEDA9681-2C11-492F-B1C9-D772BB45730A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6869E5BF-551A-40F1-9B6B-D1B27A5676CB}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

Двоичные данные
Canon/README.md Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1,123 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
// Overview of amplitude amplification library
// ===========================================
//
// Oblivious amplitude amplification with partial reflections is the most
// Oblivious amplitude amplification with partial reflections is the most
// general form of amplitude amplification implemented here.
//
// This is called through the operation AmpAmpObliviousByReflectionPhases.
//
// This has two registers: `ancillaRegister` and `systemRegister`.
//
// This accepts two oracles for these reflections of type
// `ReflectionOracle` which act only on the `ancillaRegister`
// This accepts two oracles for these reflections of type
// `ReflectionOracle` which act only on the `ancillaRegister`
// register.
//
// This accepts an oracle special to oblivious amplitude
// amplification of type `ObliviousOracle` which acts jointly
// This accepts an oracle special to oblivious amplitude
// amplification of type `ObliviousOracle` which acts jointly
// on both register.
//
// The input state to `ancillaRegister` is assumed to be the unique
// The input state to `ancillaRegister` is assumed to be the unique
// $-1$ eigenstate of the first reflection operator $I - 2\ket{s}\bra{s}$.
//
// Reflections about a target quantum state are often implemented by
// assuming access to an oracle that prepare that state from the
// Reflections about a target quantum state are often implemented by
// assuming access to an oracle that prepare that state from the
// computational basis $\ket{0\cdots 0}$.
//
// Our convention for these oracles requires two registers: a
// single-qubit `flagQubit` register, and a register for everything
// Our convention for these oracles requires two registers: a
// single-qubit `flagQubit` register, and a register for everything
// else on the ancillaRegister register.
//
// The oracle of type `StateOracle` acts jointly on both registers to
// create the target state flagged by $\ket{1}$ in the `flagQubit`
// create the target state flagged by $\ket{1}$ in the `flagQubit`
// register with some real amplitude.
//
// The reflection `ReflectionOracle` about the this flag state is
// The reflection `ReflectionOracle` about the this flag state is
// generated by the operation `TargetStateReflectionOracle`.
//
// The reflection `ReflectionOracle` about the input state to
// `ancillaRegister` is generated by the inverting StateOracle and
// The reflection `ReflectionOracle` about the input state to
// `ancillaRegister` is generated by the inverting StateOracle and
// then reflecting about $\ket{0\cdots 0}$ with ReflectionStart().
//
// The oracle of type `DeterministicStateOracle` acts on the
// `qubitState` registers to create the target state exactly with no
// The oracle of type `DeterministicStateOracle` acts on the
// `qubitState` registers to create the target state exactly with no
// flag.
//
// `AmpAmpObliviousByOraclePhases` is a version of oblivious amplitude
// amplification that accepts oracles `StateOracle` and `ObliviousOracle`
// amplification that accepts oracles `StateOracle` and `ObliviousOracle`
// instead of reflections.
//
// Note that amplitude amplification is a special case of oblivious
// Note that amplitude amplification is a special case of oblivious
// amplitude amplifiction where `ObliviousOracle` is the identity operator,
// and there are no system qubits i.e. `systemRegister` is empty.
//
// This is called through the operation `AmpAmByReflectionPhases` and
// This is called through the operation `AmpAmByReflectionPhases` and
// `AmpAmpByOraclePhases`.
//
// The phases for partial reflections in the standard case of Grover
// The phases for partial reflections in the standard case of Grover
// search is provided by the function AmpAmpPhasesStandard.
//
// For instance, we have the following dependencies: AmpAmpByOracle ->
// AmpAmpByOraclePhases -> AmpAmpObliviousByOraclePhases ->
// For instance, we have the following dependencies: AmpAmpByOracle ->
// AmpAmpByOraclePhases -> AmpAmpObliviousByOraclePhases ->
// AmpAmpObliviousByReflectionPhases.
/// # Summary
/// Converts phases specified as single-qubit rotations to phases
/// Converts phases specified as single-qubit rotations to phases
/// specified as partial reflections.
///
/// # Input
/// ## rotPhases
/// Array of single-qubit rotations to be converted to partial
/// Array of single-qubit rotations to be converted to partial
/// reflections.
///
/// # Output
/// An operation that implements phases specified as partial reflections.
///
/// # References
/// We use the convention in
/// - [ *G.H. Low, I. L. Chuang* ](https://arxiv.org/abs/1707.05391)
/// We use the convention in
/// - [ *G.H. Low, I. L. Chuang* ](https://arxiv.org/abs/1707.05391)
/// for relating single-qubit rotation phases to reflection operator phases.
function AmpAmpRotationToReflectionPhases( rotPhases : AmpAmpRotationPhases) : AmpAmpReflectionPhases
function AmpAmpRotationToReflectionPhases (rotPhases : AmpAmpRotationPhases) : AmpAmpReflectionPhases
{
let nPhasesRot = Length(rotPhases);
let nPhasesRot = Length(rotPhases!);
let nPhasesRef = (nPhasesRot + 1) / 2;
if (nPhasesRot % 2 == 0) {
fail "Number of rotations must be odd.";
if (nPhasesRot % 2 == 0)
{
fail $"Number of rotations must be odd.";
}
mutable phasesTarget = new Double[nPhasesRef];
mutable phasesStart = new Double[nPhasesRef];
set phasesTarget[0] = rotPhases[0] - rotPhases[1] - PI();
set phasesStart[0] = - rotPhases[0] + 0.5 * PI();
for (idxPhases in 1..nPhasesRef - 2){
set phasesTarget[idxPhases] = rotPhases[2*idxPhases] - rotPhases[2*idxPhases + 1] - PI();
set phasesStart[idxPhases] = rotPhases[2*idxPhases-1] - rotPhases[2*idxPhases] + PI();
set phasesTarget[0] = ((rotPhases!)[0] - (rotPhases!)[1]) - PI();
set phasesStart[0] = -(rotPhases!)[0] + 0.5 * PI();
for (idxPhases in 1 .. nPhasesRef - 2)
{
set phasesTarget[idxPhases] = ((rotPhases!)[2 * idxPhases] - (rotPhases!)[2 * idxPhases + 1]) - PI();
set phasesStart[idxPhases] = ((rotPhases!)[2 * idxPhases - 1] - (rotPhases!)[2 * idxPhases]) + PI();
}
set phasesTarget[nPhasesRef-1] = rotPhases[2*nPhasesRef-2] - 0.5 * PI();
set phasesStart[nPhasesRef-1] = rotPhases[2*nPhasesRef-3] - rotPhases[2*nPhasesRef-2] + PI();
set phasesTarget[nPhasesRef - 1] = (rotPhases!)[2 * nPhasesRef - 2] - 0.5 * PI();
set phasesStart[nPhasesRef - 1] = ((rotPhases!)[2 * nPhasesRef - 3] - (rotPhases!)[2 * nPhasesRef - 2]) + PI();
return AmpAmpReflectionPhases(phasesStart, phasesTarget);
}
/// # Summary
/// Computes partial reflection phases for standard amplitude
/// amplification.
///
/// # Input
/// ## nIterations
/// Number of amplitude amplification iterations to generate partial
/// Number of amplitude amplification iterations to generate partial
/// reflection phases for.
///
/// # Output
@ -126,33 +130,35 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// All phases are $\pi$, except for the first reflection about the start
/// state and the last reflection about the target state, which are $0$.
function AmpAmpPhasesStandard(nIterations : Int) : AmpAmpReflectionPhases {
mutable phasesTarget = new Double[nIterations+1];
mutable phasesStart = new Double[nIterations+1];
for (idxPhases in 0..nIterations){
function AmpAmpPhasesStandard (nIterations : Int) : AmpAmpReflectionPhases
{
mutable phasesTarget = new Double[nIterations + 1];
mutable phasesStart = new Double[nIterations + 1];
for (idxPhases in 0 .. nIterations)
{
set phasesTarget[idxPhases] = PI();
set phasesStart[idxPhases] = PI();
}
set phasesTarget[nIterations] = 0.0;
set phasesStart[0] = 0.0;
return AmpAmpReflectionPhases(phasesStart, phasesTarget);
}
// We use the phases in "Fixed-Point Amplitude Amplification with an
// We use the phases in "Fixed-Point Amplitude Amplification with an
// Optimal Number of Queires" [YoderLowChuang2014]
// See also "Methodology of composite quantum gates" [LowYoderChuang2016]
// See also "Methodology of composite quantum gates" [LowYoderChuang2016]
// for phases in the `AmpAmpRotationPhases` format
/// # Summary
/// Computes partial reflection phases for fixed-point amplitude
/// Computes partial reflection phases for fixed-point amplitude
/// amplification.
///
/// # Input
/// ## nQueries
/// Number of queries to the state preparation oracle. Must be an odd
/// Number of queries to the state preparation oracle. Must be an odd
/// integer.
/// ## successMin
/// Target minimum success probability.
@ -163,110 +169,119 @@ namespace Microsoft.Quantum.Canon {
///
/// # References
/// We use the phases in "Fixed-Point Amplitude Amplification with
/// an Optimal Number of Queries"
/// an Optimal Number of Queries"
/// - [YoderLowChuang2014](https://arxiv.org/abs/1409.3305)
/// See also "Methodology of composite quantum gates"
/// See also "Methodology of composite quantum gates"
/// - [LowYoderChuang2016](https://arxiv.org/abs/1603.03996)
/// for phases in the `AmpAmpRotationPhases` format.
function AmpAmpPhasesFixedPoint( nQueries: Int, successMin: Double ) : AmpAmpReflectionPhases
function AmpAmpPhasesFixedPoint (nQueries : Int, successMin : Double) : AmpAmpReflectionPhases
{
mutable phasesRot = new Double[nQueries];
let nQueriesDouble = ToDouble(nQueries);
set phasesRot[0] = 0.0;
let beta = Cosh(1.0 / nQueriesDouble * ArcCosh( Sqrt(successMin) ));
for (idxPhases in 1..nQueries - 1){
set phasesRot[idxPhases] = phasesRot[idxPhases - 1] + 2.0 * ArcTan( Tan( 2.0 * 1.0 * ToDouble(idxPhases) * PI() / nQueriesDouble ) * Sqrt(1.0 - beta * beta));
let beta = Cosh((1.0 / nQueriesDouble) * ArcCosh(Sqrt(successMin)));
for (idxPhases in 1 .. nQueries - 1)
{
set phasesRot[idxPhases] = phasesRot[idxPhases - 1] + 2.0 * ArcTan(Tan((((2.0 * 1.0) * ToDouble(idxPhases)) * PI()) / nQueriesDouble) * Sqrt(1.0 - beta * beta));
}
return AmpAmpRotationToReflectionPhases(AmpAmpRotationPhases(phasesRot));
}
/// # Summary
/// Oblivious amplitude amplification by specifying partial reflections.
///
/// # Input
/// ## phases
/// Phases of partial reflections
/// Phases of partial reflections
/// ## ancillaReflection
/// Reflection operator about start state of ancilla register
/// Reflection operator about start state of ancilla register
/// ## targetStateReflection
/// Reflection operator about target state of ancilla register
/// Reflection operator about target state of ancilla register
/// ## signalOracle
/// Unitary oracle $O$ of type `ObliviousOracle` that acts jointly on the
/// Unitary oracle $O$ of type `ObliviousOracle` that acts jointly on the
/// ancilla and system registers.
/// ## ancillaRegister
/// Ancilla register
/// Ancilla register
/// ## systemRegister
/// System register
/// System register
///
/// # Remarks
/// Given a particular ancilla start state $\ket{\text{start}}\_a$, a
/// particular ancilla target state $\ket{\text{target}}\_a$, and any
/// system state $\ket{\psi}\_s$, suppose that
/// Given a particular ancilla start state $\ket{\text{start}}\_a$, a
/// particular ancilla target state $\ket{\text{target}}\_a$, and any
/// system state $\ket{\psi}\_s$, suppose that
/// \begin{align}
/// O\ket{\text{start}}\_a\ket{\psi}\_s= \lambda\ket{\text{target}}\_a U \ket{\psi}\_s + \sqrt{1-|\lambda|^2}\ket{\text{target}^\perp}\_a\cdots
/// \end{align}
/// for some unitary $U$.
/// By a sequence of reflections about the start and target states on the
/// ancilla register interleaved by applications of `signalOracle` and its
/// ancilla register interleaved by applications of `signalOracle` and its
/// adjoint, the success probability of applying U may be altered.
///
/// In most cases, `ancillaRegister` is initialized in the state $\ket{\text{start}}\_a$.
///
/// # References
/// See
/// - [ *D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma* ](https://arxiv.org/abs/1312.1414)
/// See
/// - [ *D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma* ](https://arxiv.org/abs/1312.1414)
/// for the standard version.
/// See
/// - [ *G.H. Low, I.L. Chuang* ](https://arxiv.org/abs/1610.06546)
/// See
/// - [ *G.H. Low, I.L. Chuang* ](https://arxiv.org/abs/1610.06546)
/// for a generalization to partial reflections.
operation AmpAmpObliviousByReflectionPhasesImpl(phases : AmpAmpReflectionPhases, ancillaReflection : ReflectionOracle, targetStateReflection : ReflectionOracle, signalOracle : ObliviousOracle, ancillaRegister: Qubit[], systemRegister: Qubit[]) : ()
operation AmpAmpObliviousByReflectionPhasesImpl (phases : AmpAmpReflectionPhases, ancillaReflection : ReflectionOracle, targetStateReflection : ReflectionOracle, signalOracle : ObliviousOracle, ancillaRegister : Qubit[], systemRegister : Qubit[]) : Unit
{
body {
let (phasesAncilla, phasesTarget) = phases;
body (...)
{
let (phasesAncilla, phasesTarget) = phases!;
let nphases = 2 * Length(phasesTarget);
//FailOn(nphases != Length(phasesAncilla), "Phase array lengths not equal.")
if(phasesAncilla[0] != 0.0) {
ancillaReflection(phasesAncilla[0], ancillaRegister);
if (phasesAncilla[0] != 0.0)
{
ancillaReflection!(phasesAncilla[0], ancillaRegister);
}
for (idxPhases in 1..nphases - 1){
let idxPhaseAncilla = (idxPhases / 2);
for (idxPhases in 1 .. nphases - 1)
{
let idxPhaseAncilla = idxPhases / 2;
let idxPhaseTarget = idxPhases / 2;
if (idxPhases % 2 == 1) {
signalOracle(ancillaRegister, systemRegister);
if (phasesTarget[idxPhaseTarget] != 0.0) {
targetStateReflection(phasesTarget[idxPhaseTarget], ancillaRegister);
if (idxPhases % 2 == 1)
{
signalOracle!(ancillaRegister, systemRegister);
if (phasesTarget[idxPhaseTarget] != 0.0)
{
targetStateReflection!(phasesTarget[idxPhaseTarget], ancillaRegister);
}
}
else {
(Adjoint signalOracle)(ancillaRegister, systemRegister);
if (phasesAncilla[idxPhaseAncilla] != 0.0) {
ancillaReflection(phasesAncilla[idxPhaseAncilla], ancillaRegister);
else
{
Adjoint signalOracle!(ancillaRegister, systemRegister);
if (phasesAncilla[idxPhaseAncilla] != 0.0)
{
ancillaReflection!(phasesAncilla[idxPhaseAncilla], ancillaRegister);
}
}
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Returns a unitary that implements oblivious amplitude amplification by specifying for partial reflections.
function AmpAmpObliviousByReflectionPhases(phases : AmpAmpReflectionPhases, ancillaReflection : ReflectionOracle, targetStateReflection : ReflectionOracle, signalOracle : ObliviousOracle) : ((Qubit[], Qubit[]) => () : Adjoint, Controlled)
function AmpAmpObliviousByReflectionPhases (phases : AmpAmpReflectionPhases, ancillaReflection : ReflectionOracle, targetStateReflection : ReflectionOracle, signalOracle : ObliviousOracle) : ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled)
{
return AmpAmpObliviousByReflectionPhasesImpl(phases, ancillaReflection, targetStateReflection, signalOracle, _, _) ;
return AmpAmpObliviousByReflectionPhasesImpl(phases, ancillaReflection, targetStateReflection, signalOracle, _, _);
}
/// # Summary
/// Oblivious amplitude amplification by oracles for partial reflections.
///
@ -292,15 +307,15 @@ namespace Microsoft.Quantum.Canon {
/// O\ket{\text{start}}\_{fa}\ket{\psi}\_s= \lambda\ket{1}\_f\ket{\text{anything}}\_a\ket{\text{target}}\_s U \ket{\psi}\_s + \sqrt{1-|\lambda|^2}\ket{0}\_f\cdots,
/// \end{align}
/// for some unitary $U$.
function AmpAmpObliviousByOraclePhases(phases : AmpAmpReflectionPhases, ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle, idxFlagQubit : Int) : ((Qubit[], Qubit[]) => () : Adjoint, Controlled)
function AmpAmpObliviousByOraclePhases (phases : AmpAmpReflectionPhases, ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle, idxFlagQubit : Int) : ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled)
{
let ancillaReflection = ReflectionStart();
let targetStateReflection = TargetStateReflectionOracle(idxFlagQubit);
let oracleObliviousNew = ObliviousOracleFromDeterministicStateOracle(ancillaOracle, signalOracle);
return AmpAmpObliviousByReflectionPhases(phases, ancillaReflection, targetStateReflection, oracleObliviousNew);
}
/// # Summary
/// Amplitude amplification by partial reflections.
///
@ -312,7 +327,7 @@ namespace Microsoft.Quantum.Canon {
/// ## targetStateReflection
/// Reflection operator about target state
/// ## startQubits
/// Qubit register
/// Qubit register
///
/// # Output
/// An operation that implements amplitude amplification by partial reflections.
@ -320,75 +335,72 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// Amplitude amplification is a special case of oblivous amplitude amplification where there are no system qubits and the oblivious oracle is set to identity.
/// In most cases, `startQubits` is initialized in the state $\ket{\text{start}}\_1$, which is the $-1$ eigenstate of `startStateReflection`
function AmpAmpByReflectionsPhases(phases : AmpAmpReflectionPhases, startStateReflection : ReflectionOracle, targetStateReflection : ReflectionOracle) : (Qubit[] => () : Adjoint, Controlled)
function AmpAmpByReflectionsPhases (phases : AmpAmpReflectionPhases, startStateReflection : ReflectionOracle, targetStateReflection : ReflectionOracle) : (Qubit[] => Unit : Adjoint, Controlled)
{
//Pass empty qubit array using fact that NoOp2 does nothing
// Pass empty qubit array using fact that NoOp does nothing.
let qubitEmpty = new Qubit[0];
let signalOracle = ObliviousOracle(NoOp2);
let signalOracle = ObliviousOracle(NoOp<(Qubit[], Qubit[])>);
return (AmpAmpObliviousByReflectionPhases(phases, startStateReflection, targetStateReflection, signalOracle))(_, qubitEmpty);
}
/// # Summary
/// Amplitude amplification by oracles for partial reflections.
///
/// # Input
/// ## phases
/// Phases of partial reflections
/// Phases of partial reflections
/// ## stateOracle
/// Unitary oracle $A$ that prepares start state
/// Unitary oracle $A$ that prepares start state
/// ## idxFlagQubit
/// Index to flag qubit
/// Index to flag qubit
/// ## qubits
/// Start state register
/// Start state register
///
/// # Output
/// An operation that implements amplitude amplification by oracles that are
/// An operation that implements amplitude amplification by oracles that are
/// implemented by partial reflections.
///
/// # Remarks
/// This imposes stricter conditions on form of the start and target states than in `AmpAmpByReflectionPhases`.
/// It is assumed that the target state is marked by $\ket{1}\_f$.
/// It is assumed that
/// It is assumed that
/// \begin{align}
/// A\ket{0}\_{f}\ket{0}\_s= \lambda\ket{1}\_f\ket{\text{target}}\_s + \sqrt{1-|\lambda|^2}\ket{0}\_f\cdots,
/// \end{align}
/// In most cases, `flagQubit` and `ancillaRegister` is initialized in the state $\ket{0}\_{f}\ket{0}\_s$.
function AmpAmpByOraclePhases(phases : AmpAmpReflectionPhases, stateOracle : StateOracle, idxFlagQubit : Int) : (Qubit[] => () : Adjoint, Controlled)
function AmpAmpByOraclePhases (phases : AmpAmpReflectionPhases, stateOracle : StateOracle, idxFlagQubit : Int) : (Qubit[] => Unit : Adjoint, Controlled)
{
let qubitEmpty = new Qubit[0];
let signalOracle = ObliviousOracle(NoOp2);
let signalOracle = ObliviousOracle(NoOp<(Qubit[], Qubit[])>);
let ancillaOracle = DeterministicStateOracleFromStateOracle(idxFlagQubit, stateOracle);
return (AmpAmpObliviousByOraclePhases(phases, ancillaOracle, signalOracle, idxFlagQubit))(_, qubitEmpty);
}
/// # Summary
/// Standard Amplitude Amplification algorithm
///
/// # Input
/// ## nIterations
/// Number of iterations $n$ of amplitude amplification
/// Number of iterations $n$ of amplitude amplification
/// ## statePrepOracle
/// Unitary oracle $A$ that prepares start state
/// Unitary oracle $A$ that prepares start state
/// ## idxFlagQubit
/// Index to flag qubit
/// Index to flag qubit
/// ## qubits
/// Start state register
/// Start state register
///
/// # Output
/// An operation that implements the standard amplitude amplification quantum algorithm
///
/// # Remarks
/// This is the standard amplitude amplification algorithm obtained by a choice of reflection phases computed by `AmpAmpPhasesStandard`
/// Assuming that
/// Assuming that
/// \begin{align}
/// A\ket{0}\_{f}\ket{0}\_s= \lambda\ket{1}\_f\ket{\text{target}}\_s + \sqrt{1-|\lambda|^2}\ket{0}\_f\cdots,
/// \end{align}
/// this operation prepares the state
/// this operation prepares the state
/// \begin{align}
/// \operatorname{AmpAmpByOracle}\ket{0}\_{f}\ket{0}\_s= \sin((2n+1)\sin^{-1}(\lambda))\ket{1}\_f\ket{\text{target}}\_s + \cdots\ket{0}\_f
/// \end{align}
@ -396,68 +408,75 @@ namespace Microsoft.Quantum.Canon {
///
/// # References
/// - [ *G. Brassard, P. Hoyer, M. Mosca, A. Tapp* ](https://arxiv.org/abs/quant-ph/0005055)
function AmpAmpByOracle(nIterations: Int, stateOracle : StateOracle, idxFlagQubit : Int) : (Qubit[] => () : Adjoint, Controlled)
function AmpAmpByOracle (nIterations : Int, stateOracle : StateOracle, idxFlagQubit : Int) : (Qubit[] => Unit : Adjoint, Controlled)
{
let phases = AmpAmpPhasesStandard(nIterations);
return AmpAmpByOraclePhases(phases, stateOracle, idxFlagQubit);
}
/// # Summary
/// Fixed-Point Amplitude Amplification algorithm
/// Fixed-Point Amplitude Amplification algorithm
///
/// # Input
/// ## statePrepOracle
/// Unitary oracle that prepares the start state.
/// ## startQubits
/// Qubit register
/// Qubit register
///
/// # Remarks
/// The startQubits must be in the $\ket{0 \cdots 0}$ state. This operation iterates over a number of queries in powers of $2$ until either a maximal number of queries
/// is reached, or the target state is found.
operation AmpAmpRUSByOracle(statePrepOracle : StateOracle, startQubits: Qubit[]) : ()
operation AmpAmpRUSByOracle (statePrepOracle : StateOracle, startQubits : Qubit[]) : Unit
{
body {
let queriesMax = 999; // Should be a power of 2
let successMin = 0.99;
mutable finished = Zero;
mutable exponentMax = 0;
mutable exponentCurrent = 0;
//Complexity: Let \theta = \mathcal{O}(\sqrt{lambda})
// Number of Measurements = O( Log^2(1/\theta) )
// Number of Queries = O(1/\theta)
using (flagQubit = Qubit[1]) {
let qubits = flagQubit + startQubits;
let idxFlagQubit = 0;
repeat {
if( 2 ^ exponentMax > queriesMax ) {
fail "Target state not found. Maximum number of queries exceeded.";
}
repeat {
let queries = 2 ^ exponentCurrent;
let phases = AmpAmpPhasesFixedPoint( queries, successMin );
(AmpAmpByOraclePhases(phases, statePrepOracle, idxFlagQubit))(qubits);
set finished = M(flagQubit[0]);
set exponentCurrent = exponentCurrent + 1;
}
until(finished == One || exponentCurrent > exponentMax)
fixup {
// flagQubit is already in Zero for fixup to apply
ResetAll(startQubits);
}
set exponentCurrent = 0;
set exponentMax = exponentMax + 1;
// Should be a power of 2
let queriesMax = 999;
let successMin = 0.99;
mutable finished = Zero;
mutable exponentMax = 0;
mutable exponentCurrent = 0;
//Complexity: Let \theta = \mathcal{O}(\sqrt{lambda})
// Number of Measurements = O( Log^2(1/\theta) )
// Number of Queries = O(1/\theta)
using (flagQubit = Qubit[1])
{
let qubits = flagQubit + startQubits;
let idxFlagQubit = 0;
repeat
{
if (2 ^ exponentMax > queriesMax)
{
fail $"Target state not found. Maximum number of queries exceeded.";
}
until(finished == One)
fixup {
repeat
{
let queries = 2 ^ exponentCurrent;
let phases = AmpAmpPhasesFixedPoint(queries, successMin);
(AmpAmpByOraclePhases(phases, statePrepOracle, idxFlagQubit))(qubits);
set finished = M(flagQubit[0]);
set exponentCurrent = exponentCurrent + 1;
}
until (finished == One || exponentCurrent > exponentMax)
fixup
{
// flagQubit is already in Zero for fixup to apply
ResetAll(startQubits);
}
set exponentCurrent = 0;
set exponentMax = exponentMax + 1;
}
until (finished == One)
fixup
{
ResetAll(startQubits);
}
}
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Represents a reflection oracle $O$, where the inputs are
/// - The phase $\phi$ by which to rotate the reflected subspace.
@ -14,15 +17,14 @@ namespace Microsoft.Quantum.Canon {
/// This oracle $O = \boldone - (1 - e^{i \phi}) \ket{\psi}\bra{\psi}$
/// performs a partial reflection by a phase $\phi$ about a single pure state
/// $\ket{\psi}$.
newtype ReflectionOracle = ((Double, Qubit[]) => (): Adjoint, Controlled);
newtype ReflectionOracle = ((Double, Qubit[]) => Unit : Adjoint, Controlled);
// This oracle O|s>_a|ψ>_s = λ |t>_a U |ψ>_s + ... acts on the ancilla state |s>_a to implement the unitary U on any system state |ψ>_s with amplitude λ in the |t>_a basis.
/// # Summary
/// Represents an oracle $O$ for oblivious amplitude amplification, where
/// Represents an oracle $O$ for oblivious amplitude amplification, where
/// the inputs are
/// - The ancilla register $a$ that $O$ acts on.
/// - The ancilla register $a$ that $O$ acts on.
/// - The system register $s$ on which the desired unitary $U$ is applied, post-selected on register $a$ being in state $\ket{t}\_a$.
///
/// # Remarks
@ -32,22 +34,22 @@ namespace Microsoft.Quantum.Canon {
/// $$
/// acts on the ancilla state $\ket{s}\_a$ to implement the unitary $U$ on any system state $\ket{\psi}\_s$ with amplitude $\lambda$ in the basis flagged by $\ket{t}\_a$.
/// The first parameter is the qubit register of $\ket{s}\_a$. The second parameter is the qubit register of $\ket{\psi}\_s$.
newtype ObliviousOracle = ((Qubit[], Qubit[]) => (): Adjoint, Controlled);
newtype ObliviousOracle = ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// Represents an oracle $O$ for state preparation, where the inputs are
/// - An integer indexing the flag qubit $f$.
/// - The system register $s$ that will store the desired quantum state $\ket{\psi}\_s$.
///
/// # Remarks
/// This oracle defined by
/// This oracle defined by
/// $$
/// O\ket{0}\_{f}\ket{0}\_s= \lambda\ket{1}\_f\ket{\psi}\_s + \sqrt{1-|\lambda|^2}\ket{0}\_f\cdots,
/// $$
/// acts on the on computational basis state $\ket{0}\_{f}\ket{0}\_s$ to create the target state $\ket{\psi}\_s$ with amplitude $\lambda$ in the basis flagged by $\ket{1}\_f$.
/// The first parameter is an index to the qubit register of $\ket{0}\_f$. The second parameter encompassed both registers.
newtype StateOracle = ((Int, Qubit[]) => (): Adjoint, Controlled);
newtype StateOracle = ((Int, Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// Represents an oracle $O$ for deterministic state preparation, where
/// the input is
@ -56,22 +58,24 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// This oracle defined by $O\ket{0}=\ket{\psi}$ acts on the on computational basis state $\ket{0}$ to create the state $\ket{\psi}$.
/// The first parameter is the qubit register of $\ket{\psi}$.
newtype DeterministicStateOracle = (Qubit[] => (): Adjoint, Controlled);
newtype DeterministicStateOracle = (Qubit[] => Unit : Adjoint, Controlled);
/// # Summary
/// Phases for a sequence of partial reflections in amplitude amplification.
///
/// # Remarks
/// The first parameter is an array of phases for reflection about the start state. The second parameter is an array of phases for reflection about the target state.
/// Both arrays must be of equal length. Note that in many cases, the first phase about the start state and last phase about the target state introduces a global phase shift and may be set to $0$.
/// Both arrays must be of equal length. Note that in many cases, the first phase about the start state and last phase about the target state introduces a global phase shift and may be set to $0$.
newtype AmpAmpReflectionPhases = (Double[], Double[]);
/// # Summary
/// Phases for a sequence of single-qubit rotations in amplitude amplification.
///
/// # Remarks
/// The first parameter is an array of phases for reflections, expressed as a product of single-qubit rotations.
/// [ G.H. Low, I. L. Chuang, https://arxiv.org/abs/1707.05391].
newtype AmpAmpRotationPhases = (Double[]);
newtype AmpAmpRotationPhases = Double[];
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// This performs a phase shift operation $R=\boldone-(1-e^{i \phi})\ket{1\cdots 1}\bra{1\cdots 1}$.
///
@ -13,22 +16,22 @@ namespace Microsoft.Quantum.Canon {
/// The phase $\phi$ applied to state $\ket{1\cdots 1}\bra{1\cdots 1}$.
/// ## qubits
/// The register whose state is to be rotated by $R$.
operation RAll1( phase: Double, qubits: Qubit[] ) : ()
operation RAll1 (phase : Double, qubits : Qubit[]) : Unit
{
body {
body (...)
{
let nQubits = Length(qubits);
let flagQubit = qubits[0];
let systemRegister = qubits[1..nQubits-1];
(Controlled R1(phase, _))(systemRegister, flagQubit);
let systemRegister = qubits[1 .. nQubits - 1];
Controlled (R1(phase, _))(systemRegister, flagQubit);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// This performs a phase shift operation $R=\boldone-(1-e^{i \phi})\ket{0\cdots 0}\bra{0\cdots 0}$.
///
@ -40,31 +43,35 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.RAll1
operation RAll0( phase: Double, qubits: Qubit[] ) : ()
operation RAll0 (phase : Double, qubits : Qubit[]) : Unit
{
body {
body (...)
{
WithCA(ApplyToEachCA(X, _), RAll1(phase, _), qubits);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.obliviousoraclefromdeterministicstateoracle>.
operation _ObliviousOracleFromDeterministicStateOracle(ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle, ancillaRegister: Qubit[], systemRegister: Qubit[]) : (){
body{
ancillaOracle(ancillaRegister);
signalOracle(ancillaRegister, systemRegister);
operation _ObliviousOracleFromDeterministicStateOracle (ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle, ancillaRegister : Qubit[], systemRegister : Qubit[]) : Unit
{
body (...)
{
ancillaOracle!(ancillaRegister);
signalOracle!(ancillaRegister, systemRegister);
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Combines the oracles `DeterministicStateOracle` and `ObliviousOracle`.
///
@ -80,56 +87,67 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.DeterministicStateOracle
/// - Microsoft.Quantum.Canon.ObliviousOracle
function ObliviousOracleFromDeterministicStateOracle(ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle) : ObliviousOracle{
return ObliviousOracle(_ObliviousOracleFromDeterministicStateOracle(ancillaOracle, signalOracle,_,_));
function ObliviousOracleFromDeterministicStateOracle (ancillaOracle : DeterministicStateOracle, signalOracle : ObliviousOracle) : ObliviousOracle
{
return ObliviousOracle(_ObliviousOracleFromDeterministicStateOracle(ancillaOracle, signalOracle, _, _));
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.deterministicstateoraclefromstateoracle>.
operation _DeterministicStateOracleFromStateOracle(idxFlagQubit: Int, stateOracle : StateOracle, startQubits: Qubit[]) : (){
body {
stateOracle(idxFlagQubit, startQubits);
operation _DeterministicStateOracleFromStateOracle (idxFlagQubit : Int, stateOracle : StateOracle, startQubits : Qubit[]) : Unit
{
body (...)
{
stateOracle!(idxFlagQubit, startQubits);
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Converts an oracle of type `StateOracle` to `DeterministicStateOracle`.
///
/// # Input
/// ## idxFlagQubit
/// The index to the flag qubit of the `stateOracle` $A$,
/// which explicitly acts on two registers: the flag $f$ and the system
/// The index to the flag qubit of the `stateOracle` $A$,
/// which explicitly acts on two registers: the flag $f$ and the system
/// $s$, e.g. $A\ket{0}\_f\ket{\psi}\_s$.
/// ## stateOracle
/// A state preparation oracle $A$ of type `StateOracle`.
///
/// # Output
/// The same state preparation oracle $A$, but now of type
/// `DeterministicStateOracle`, so it acts on a register where $a,s$ no
/// The same state preparation oracle $A$, but now of type
/// `DeterministicStateOracle`, so it acts on a register where $a,s$ no
/// longer explicitly separate, e.g. $A\ket{0\psi}\_{as}$.
///
/// # See Also
/// # See Also
/// - Microsoft.Quantum.Canon.StateOracle
/// - Microsoft.Quantum.Canon.DeterministicStateOracle
function DeterministicStateOracleFromStateOracle(idxFlagQubit: Int, stateOracle : StateOracle) : DeterministicStateOracle{
return DeterministicStateOracle(_DeterministicStateOracleFromStateOracle(idxFlagQubit, stateOracle,_));
function DeterministicStateOracleFromStateOracle (idxFlagQubit : Int, stateOracle : StateOracle) : DeterministicStateOracle
{
return DeterministicStateOracle(_DeterministicStateOracleFromStateOracle(idxFlagQubit, stateOracle, _));
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.stateoraclefromdeterministicstateoracle>.
operation _StateOracleFromDeterministicStateOracle(idxFlagQubit : Int, oracleStateDeterministic : DeterministicStateOracle, qubits: Qubit[]): ()
operation _StateOracleFromDeterministicStateOracle (idxFlagQubit : Int, oracleStateDeterministic : DeterministicStateOracle, qubits : Qubit[]) : Unit
{
body {
oracleStateDeterministic(qubits);
body (...)
{
oracleStateDeterministic!(qubits);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Converts an oracle of type `DeterministicStateOracle` to `StateOracle`.
///
@ -145,21 +163,27 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.DeterministicStateOracle
/// - Microsoft.Quantum.Canon.StateOracle
function StateOracleFromDeterministicStateOracle(deterministicStateOracle : DeterministicStateOracle) : StateOracle {
return StateOracle(_StateOracleFromDeterministicStateOracle(_, deterministicStateOracle,_));
function StateOracleFromDeterministicStateOracle (deterministicStateOracle : DeterministicStateOracle) : StateOracle
{
return StateOracle(_StateOracleFromDeterministicStateOracle(_, deterministicStateOracle, _));
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.reflectionstart>.
operation _ReflectionStart(phase: Double, qubits: Qubit[] ) : () {
body {
RAll0(phase, qubits );
operation _ReflectionStart (phase : Double, qubits : Qubit[]) : Unit
{
body (...)
{
RAll0(phase, qubits);
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Constructs a reflection about the all-zero string $\ket{0\cdots 0}$, which is the typical input state to amplitude amplification.
///
@ -168,22 +192,27 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ReflectionOracle
function ReflectionStart() : ReflectionOracle {
return ReflectionOracle(_ReflectionStart( _, _ ));
function ReflectionStart () : ReflectionOracle
{
return ReflectionOracle(_ReflectionStart(_, _));
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.reflectionoraclefromdeterministicstateoracle>.
operation ReflectionOracleFromDeterministicStateOracleImpl(phase: Double, oracle: DeterministicStateOracle, systemRegister: Qubit[]): ()
operation ReflectionOracleFromDeterministicStateOracleImpl (phase : Double, oracle : DeterministicStateOracle, systemRegister : Qubit[]) : Unit
{
body {
WithCA((Adjoint oracle), RAll0(phase, _), systemRegister);
body (...)
{
WithCA(Adjoint oracle!, RAll0(phase, _), systemRegister);
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Constructs reflection about a some state $\ket{\psi}$ from the oracle $O$ of type
/// <xref:microsoft.quantum.canon.deterministicstateoracle>, where $O\ket{0} = \ket{\psi}$.
@ -198,24 +227,27 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.DeterministicStateOracle
/// - Microsoft.Quantum.Canon.ReflectionOracle
function ReflectionOracleFromDeterministicStateOracle(oracle: DeterministicStateOracle): ReflectionOracle
function ReflectionOracleFromDeterministicStateOracle (oracle : DeterministicStateOracle) : ReflectionOracle
{
return ReflectionOracle(ReflectionOracleFromDeterministicStateOracleImpl(_, oracle, _ ));
return ReflectionOracle(ReflectionOracleFromDeterministicStateOracleImpl(_, oracle, _));
}
/// # Summary
/// Implementation of <xref:microsoft.quantum.canon.targetstatereflectionoracle>.
operation TargetStateReflectionOracleImpl(phase: Double, idxFlagQubit : Int, qubits: Qubit[]): ()
operation TargetStateReflectionOracleImpl (phase : Double, idxFlagQubit : Int, qubits : Qubit[]) : Unit
{
body {
body (...)
{
R1(phase, qubits[idxFlagQubit]);
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Constructs reflection about the target state uniquely marked by the flag qubit state
/// $\ket{1}_f$, prepared the oracle of type "ReflectionOracle".
@ -229,10 +261,11 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ReflectionOracle
function TargetStateReflectionOracle(idxFlagQubit : Int): ReflectionOracle
function TargetStateReflectionOracle (idxFlagQubit : Int) : ReflectionOracle
{
return ReflectionOracle(TargetStateReflectionOracleImpl( _ , idxFlagQubit , _ ));
return ReflectionOracle(TargetStateReflectionOracleImpl(_, idxFlagQubit, _));
}
}

Просмотреть файл

@ -0,0 +1,734 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// If true, enables extra asserts that are expensive, but useful to debug the use of
/// the arithmetic functions.
///
/// # Remarks
/// This function allows to configure the behavior of the library.
function _EnableExtraAssertsForArithmetic () : Bool
{
return false;
}
/// # Summary
/// Let us denote `value` by a and let y be an unsigned integer encoded in `target`,
/// then `InPlaceXorLE` performs an operation given by the following map:
/// $\ket{y}\rightarrow \ket{y\oplus a}$ , where $\oplus$ is the bitwise exclusive OR operator.
///
/// # Input
/// ## value
/// An integer which is assumed to be non-negative.
/// ## target
/// A quantum register which is used to store `value` in little-endian encoding.
///
/// # See Also
/// - InPlaceXorLE
operation InPlaceXorLE (value : Int, target : LittleEndian) : Unit
{
body (...)
{
let bitrepresentation = BoolArrFromPositiveInt(value, Length(target!));
for (idx in 0 .. Length(target!) - 1)
{
if (bitrepresentation[idx])
{
X((target!)[idx]);
}
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Let us denote `value` by a and let y be an unsigned integer encoded in `target`,
/// then `InPlaceXorBE` performs an operation given by the following map:
/// $\ket{y}\rightarrow \ket{y\oplus a}$ , where $\oplus$ is the bitwise exclusive OR operator.
///
/// # Input
/// ## value
/// An integer which is assumed to be non-negative.
/// ## target
/// A quantum register which is used to store `value` in big-endian encoding.
///
/// # See Also
/// - InPlaceXorBE
operation InPlaceXorBE(value : Int, target : BigEndian) : Unit {
body (...) {
ApplyReversedOpLittleEndianCA(InPlaceXorLE(value, _), target);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This computes the Majority function in-place on $3$ bits.
///
/// # Input
/// ## output
/// First input qubit. Note that the output is computed in-place
/// and stored in this qubit.
/// ## Input
/// Second and third input qubits.
operation InPlaceMajority(output: Qubit, input: Qubit[]) : Unit {
body (...){
if(Length(input) != 2){
fail $"Majority on {input} qubits not implemented.";
}
CNOT(output, input[1]);
CNOT(output, input[0]);
CCNOT(input[1], input[0], output);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This unitary $U$ tests if two integers $x,y$ stored in equal-size qubit registers
/// satisfies $x > y$. If true, $1$ is XORed into an output
/// qubit. Otherwise, $0$ is XORed into an output qubit. In other words,
/// $$
/// \begin{align}
/// U\ket{x}\ket{y}\ket{z}=\ket{x}\ket{y}\ket{z\oplus (x>y)}.
/// \end{align}
/// $$.
///
/// # Input
/// ## x
/// First nubmer to be compared stored in `LittleEndian` format in a qubit register.
/// ## y
/// Second nubmer to be compared stored in `LittleEndian` format in a qubit register.
/// ## output
/// Qubit that stores the result of the comparison $x>y$.
///
/// # References
/// - A new quantum ripple-carry addition circuit
/// Steven A. Cuccaro, Thomas G. Draper, Samuel A. Kutin, David Petrie Moulton
/// https://arxiv.org/abs/quant-ph/0410184
operation ApplyRippleCarryComparatorLE(x: LittleEndian, y: LittleEndian, output: Qubit) : Unit {
body (...){
let nQubitsX = Length(x!);
let nQubitsY = Length(y!);
if (nQubitsX != nQubitsY){
fail "Size of integer registers must be equal.";
}
using(auxillary = Qubit[1]){
WithCA(
ApplyRippleCarryComparatorLE_(x, y, auxillary, _),
BindCA([X, CNOT(x![nQubitsX-1], _)]),
output
);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
// Implementation step of `ApplyRippleCarryComparatorLE`.
operation ApplyRippleCarryComparatorLE_(x: LittleEndian, y: LittleEndian, auxillary: Qubit[], output: Qubit) : Unit {
body (...) {
let nQubitsX = Length(x!);
// Take 2's complement
ApplyToEachCA(X, x! + auxillary);
InPlaceMajority(x![0], [y![0], auxillary[0]]);
for(idx in 1..nQubitsX - 1){
InPlaceMajority(x![idx], [x![idx - 1], y![idx]]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// Converts a `LittleEndian` qubit register to a `BigEndian` Qubit
/// register by reversing the qubit ordering.
///
/// # Input
/// ## input
/// Qubit register in `LittleEndian` format.
///
/// # Output
/// Qubit register in `BigEndian` format.
function LittleEndianToBigEndian(input: LittleEndian) : BigEndian {
return BigEndian(Reverse(input!));
}
/// # Summary
/// Converts a `BigEndian` qubit register to a `LittleEndian` Qubit
/// register by reversing the qubit ordering.
///
/// # Input
/// ## input
/// Qubit register in `BigEndian` format.
///
/// # Output
/// Qubit register in `LittleEndian` format.
function BigEndianToLittleEndian(input: BigEndian) : LittleEndian {
return LittleEndian(Reverse(input!));
}
/// # Summary
/// This unitary $U$ tests if two integers $x,y$ stored in equal-size qubit registers
/// satisfies $x > y$. If true, $1$ is XORed into an output
/// qubit. Otherwise, $0$ is XORed into an output qubit. In other words,
/// $$
/// \begin{align}
/// U\ket{x}\ket{y}\ket{z}=\ket{x}\ket{y}\ket{z\oplus (x>y)}.
/// \end{align}
/// $$.
///
/// # Input
/// ## x
/// First nubmer to be compared stored in `BigEndian` format in a qubit register.
/// ## y
/// Second nubmer to be compared stored in `BigEndian` format in a qubit register.
/// ## output
/// Qubit that stores the result of the comparison $x>y$.
///
/// # References
/// - A new quantum ripple-carry addition circuit
/// Steven A. Cuccaro, Thomas G. Draper, Samuel A. Kutin, David Petrie Moulton
/// https://arxiv.org/abs/quant-ph/0410184
operation ApplyRippleCarryComparatorBE(x: BigEndian, y: BigEndian, output: Qubit) : Unit {
body (...){
ApplyRippleCarryComparatorLE(BigEndianToLittleEndian(x), BigEndianToLittleEndian(y), output);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// `MeasureInteger` reads out the content of a quantum register and converts
/// it to an integer of type `Int`. The measurement is performed with respect
/// to the standard computational basis, i.e., the eigenbasis of `PauliZ`.
///
/// # Input
/// ## target
/// A quantum register which is assumed to be in little-endian encoding.
///
/// # Output
/// An unsigned integer that contains the measured value of `target`.
///
/// # Remarks
/// Ensures that the register is set to 0.
///
/// # See Also
/// - Microsoft.Quantum.Canon.MeasureIntegerBE
operation MeasureInteger (target : LittleEndian) : Int
{
mutable results = new Result[Length(target!)];
for (idx in 0 .. Length(target!) - 1)
{
set results[idx] = MResetZ((target!)[idx]);
}
return PositiveIntFromResultArr(results);
}
/// # Summary
/// Version of MeasureInteger for BigEndian register
///
/// # See Also
/// - Microsoft.Quantum.Canon.MeasureInteger
operation MeasureIntegerBE (target : BigEndian) : Int
{
mutable results = new Result[Length(target!)];
for (idx in 0 .. Length(target!) - 1)
{
set results[idx] = MResetZ((target!)[idx]);
}
return PositiveIntFromResultArr(Reverse(results));
}
/// # Summary
/// Unsigned integer increment by an integer constant, based on phase rotations.
/// Suppose `target` encodes unsigned integer x in little-endian encoding and
/// `increment` is equal to a.
/// The operation implements the unitary |x⟩ ↦ |x + a ⟩,
/// where the addition is performed
/// modulo 2ⁿ, for n = `Length(target)`.
///
/// # Input
/// ## target
/// Quantum register encoding an integer using little-endian encoding in QFT basis.
/// ## increment
/// The integer by which the `target` is incremented by.
///
/// # See Also
/// - Microsoft.Quantum.Canon.IntegerIncrementLE"
///
/// # References
/// - [ *Thomas G. Draper*,
/// arXiv:quant-ph/0008033](https://arxiv.org/pdf/quant-ph/0008033v1.pdf)
///
/// # Remarks
/// Note that we have simplified the circuit because the increment is a classical constant,
/// not a quantum register.
///
/// See the figure on
/// [ Page 6 of arXiv:quant-ph/0008033v1 ](https://arxiv.org/pdf/quant-ph/0008033.pdf#page=6)
/// for the circuit diagram and explanation.
operation IntegerIncrementPhaseLE (increment : Int, target : PhaseLittleEndian) : Unit
{
body (...)
{
let d = Length(target!);
for (j in 0 .. d - 1)
{
// Use Microsoft.Quantum.Primitive.R1Frac
R1Frac(increment, (d - 1) - j, (target!)[j]);
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Asserts that the highest qubit of a qubit register
/// representing an unsigned integer is in a particular state.
///
/// # Input
/// ## value
/// The value of the highest bit being asserted.
/// ## number
/// Unsigned integer of which the highest bit is checked.
///
/// # Remarks
/// The controlled version of this operation ignores controls.
///
/// # See Also
/// - Microsoft.Quantum.Primitive.Assert
operation AssertHighestBit (value : Result, number : LittleEndian) : Unit
{
body (...)
{
let mostSingificantQubit = Tail(number!);
Assert([PauliZ], [mostSingificantQubit], value, $"Most significant bit expected to be {value}");
}
adjoint self;
controlled (ctrls, ...)
{
AssertHighestBit(value, number);
}
controlled adjoint (ctrls, ...)
{
Controlled AssertHighestBit(ctrls, (value, number));
}
}
/// # Summary
/// Asserts that the `number` encoded in PhaseLittleEndian is less than `value`.
///
/// # Input
/// ## value
/// `number` must be less than this.
/// ## number
/// Unsigned integer which is compared to `value`.
///
/// # Remarks
/// The controlled version of this operation ignores controls.
operation AssertLessThanPhaseLE (value : Int, number : PhaseLittleEndian) : Unit
{
body (...)
{
let inner = ApplyLEOperationOnPhaseLEA(AssertHighestBit(One, _), _);
WithA(Adjoint IntegerIncrementPhaseLE(value, _), inner, number);
}
adjoint self;
controlled (ctrls, ...)
{
AssertLessThanPhaseLE(value, number);
}
controlled adjoint (ctrls, ...)
{
Controlled AssertLessThanPhaseLE(ctrls, (value, number));
}
}
/// # Summary
/// Unsigned integer increment by an integer constant, based on phase rotations.
/// Suppose `target` encodes unsigned integer x in little-endian encoding and
/// `increment` is equal to a.
/// The operation implements the unitary |x⟩ ↦ |x + a ⟩,
/// where the addition is performed
/// modulo 2ⁿ, for n = `Length(target)`.
///
/// # Input
/// ## target
/// Quantum register encoding an unsigned integer using little-endian encoding.
/// ## increment
/// The integer by which the `target` is incremented by
///
/// # See Also
/// - Microsoft.Quantum.Canon.IntegerIncrementPhaseLE
operation IntegerIncrementLE (increment : Int, target : LittleEndian) : Unit
{
body (...)
{
let inner = IntegerIncrementPhaseLE(increment, _);
ApplyPhaseLEOperationOnLECA(inner, target);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Let us denote `increment` by a, `modulus` by N and integer encoded in `target` by y
/// Then the operation performs the following transformation:
/// \begin{align}
/// \ket{y} \mapsto \ket{y + 1 \operatorname{mod} N}
/// \end{align}
/// Integers are encoded in little-endian format.
///
/// # Input
/// ## increment
/// Integer increment a to be added to y.
/// ## modulus
/// Integer N that mods y + a.
/// ## target
/// Integer y in `LittleEndian` format that `increment` a is added to.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ModularIncrementPhaseLE
///
/// # Remarks
/// Assumes that the value of target is less than N. Note that
/// <xref:microsoft.quantum.canon.modularincrementphasele> implements
/// the same operation, but in the `PhaseLittleEndian` basis.
operation ModularIncrementLE (increment : Int, modulus : Int, target : LittleEndian) : Unit
{
body (...)
{
let inner = ModularIncrementPhaseLE(increment, modulus, _);
using (ancilla = Qubit[1])
{
let extraZeroBit = ancilla[0];
ApplyPhaseLEOperationOnLECA(inner, LittleEndian(target! + [extraZeroBit]));
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Copies the most significant bit of a qubit register
/// `from` representing an unsigned integer into the qubit `target`.
///
/// # Input
/// ## from
/// The unsigned integer from which the highest bit is copied from.
/// the integer is encoded in little-endian format.
/// ## target
/// The qubit in which the highest bit is being copied. The bit encoding is
/// in computational basis.
///
/// # See Also
/// - Microsoft.Quantum.Canon.LittleEndian
operation CopyMostSignificantBitLE (from : LittleEndian, target : Qubit) : Unit
{
body (...)
{
let mostSingificantQubit = Tail(from!);
CNOT(mostSingificantQubit, target);
}
adjoint invert;
}
/// # Summary
/// Let us denote `increment` by a, `modulus` by N and integer encoded in `target` by y
/// Then the operation performs the following transformation:
/// |y⟩ ↦ |y+a (mod N)⟩
/// Integers are encoded in little-endian format in QFT basis
///
/// # See Also
/// - Microsoft.Quantum.Canon.ModularIncrementLE
///
/// # Remarks
/// Assumes that `target` has the highest bit set to 0.
/// Also assumes that the value of target is less than N.
///
/// For the circuit diagram and explanation see Figure 5 on [Page 5
/// of arXiv:quant-ph/0205095v3](https://arxiv.org/pdf/quant-ph/0205095v3.pdf#page=5).
operation ModularIncrementPhaseLE (increment : Int, modulus : Int, target : PhaseLittleEndian) : Unit
{
body (...)
{
AssertBoolEqual(modulus <= 2 ^ (Length(target!) - 1), true, $"`multiplier` must be big enough to fit integers modulo `modulus`" + $"with highest bit set to 0");
if (_EnableExtraAssertsForArithmetic())
{
// assert that the highest bit is zero, by switching to computational basis
ApplyLEOperationOnPhaseLEA(AssertHighestBit(Zero, _), target);
// check that the input is less than modulus
AssertLessThanPhaseLE(modulus, target);
}
using (ancilla = Qubit[1])
{
let lessThanModulusFlag = ancilla[0];
let copyMostSignificantBitPhaseLE = ApplyLEOperationOnPhaseLEA(CopyMostSignificantBitLE(_, lessThanModulusFlag), _);
// lets track the state of target register through the computation
IntegerIncrementPhaseLE(increment, target);
// the state is |x+a⟩ in QFT basis
Adjoint IntegerIncrementPhaseLE(modulus, target);
// the state is |x+a-N⟩ in QFT basis
copyMostSignificantBitPhaseLE(target);
// lessThanModulusFlag is set to 1 if x+a < N
Controlled IntegerIncrementPhaseLE([lessThanModulusFlag], (modulus, target));
// the state is |x+a (mod N)⟩ in QFT basis
// Now let us restore the lessThanModulusFlag qubit back to zero
Adjoint IntegerIncrementPhaseLE(increment, target);
X(lessThanModulusFlag);
copyMostSignificantBitPhaseLE(target);
IntegerIncrementPhaseLE(increment, target);
}
}
adjoint invert;
controlled (controls, ...)
{
AssertBoolEqual(modulus <= 2 ^ (Length(target!) - 1), true, $"`multiplier` must be big enough to fit integers modulo `modulus`" + $"with highest bit set to 0");
if (_EnableExtraAssertsForArithmetic())
{
// assert that the highest bit is zero, by switching to computational basis
ApplyLEOperationOnPhaseLEA(AssertHighestBit(Zero, _), target);
// check that the input is less than modulus
AssertLessThanPhaseLE(modulus, target);
}
// note that controlled version is correct only under the assumption
// that the value of target is less than modulus
using (ancilla = Qubit[1])
{
let lessThanModulusFlag = ancilla[0];
let copyMostSignificantBitPhaseLE = ApplyLEOperationOnPhaseLEA(CopyMostSignificantBitLE(_, lessThanModulusFlag), _);
// lets track the state of target register through the computation
Controlled IntegerIncrementPhaseLE(controls, (increment, target));
// the state is |x+a⟩ in QFT basis
Adjoint IntegerIncrementPhaseLE(modulus, target);
// the state is |x+a-N⟩ in QFT basis
copyMostSignificantBitPhaseLE(target);
// lessThanModulusFlag is set to 1 if x+a < N
Controlled IntegerIncrementPhaseLE([lessThanModulusFlag], (modulus, target));
// the state is |x+a (mod N)⟩ in QFT basis
// Now let us restore the lessThanModulusFlag qubit back to zero
Controlled (Adjoint IntegerIncrementPhaseLE)(controls, (increment, target));
X(lessThanModulusFlag);
copyMostSignificantBitPhaseLE(target);
Controlled IntegerIncrementPhaseLE(controls, (increment, target));
}
}
controlled adjoint invert;
}
/// # Summary
/// Implements the map
/// $$
/// \begin{align}
/// \ket{x} \ket{b} \mapsto \ket{x} \ket{b + a \cdot x \operatorname{mod} N}
/// \end{align}
/// $$
/// for a given modulus $N$, constant multiplier $a$, and summand $y$.
///
/// # Input
/// ## constantMultiplier
/// An integer $a$ to be added to each basis state label.
/// ## modulus
/// The modulus $N$ which addition and multiplication is taken with respect to.
/// ## multiplier
/// A quantum register representing an unsigned integer whose value is to
/// be added to each basis state label of `summand`.
/// ## summand
/// A quantum register representing an unsigned integer to use as the target
/// for this operation.
///
/// # Remarks
/// - For the circuit diagram and explanation see Figure 6 on [Page 7
/// of arXiv:quant-ph/0205095v3](https://arxiv.org/pdf/quant-ph/0205095v3.pdf#page=7)
/// - This operation corresponds to CMULT(a)MOD(N) in
/// [arXiv:quant-ph/0205095v3](https://arxiv.org/pdf/quant-ph/0205095v3.pdf)
operation ModularAddProductLE (constMultiplier : Int, modulus : Int, multiplier : LittleEndian, summand : LittleEndian) : Unit
{
body (...)
{
let inner = ModularAddProductPhaseLE(constMultiplier, modulus, multiplier, _);
using (ancilla = Qubit[1])
{
let extraZeroBit = ancilla[0];
ApplyPhaseLEOperationOnLECA(inner, LittleEndian(summand! + [extraZeroBit]));
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// The same as ModularAddProductInPlaceLE, but assumes that summand encodes
/// integers in QFT basis
///
/// # See Also
/// - Microsoft.Quantum.Canon.ModularAddProductLE
///
/// # Remarks
/// Assumes that `phaseSummand` has the highest bit set to 0.
/// Also assumes that the value of `phaseSummand` is less than N.
operation ModularAddProductPhaseLE (constMultiplier : Int, modulus : Int, multiplier : LittleEndian, phaseSummand : PhaseLittleEndian) : Unit
{
body (...)
{
AssertBoolEqual(modulus <= 2 ^ (Length(phaseSummand!) - 1), true, $"`multiplier` must be big enough to fit integers modulo `modulus`" + $"with highest bit set to 0");
AssertBoolEqual(constMultiplier >= 0 && constMultiplier < modulus, true, $"`constMultiplier` must be between 0 and `modulus`-1");
if (_EnableExtraAssertsForArithmetic())
{
// assert that the highest bit is zero, by switching to computational basis
ApplyLEOperationOnPhaseLECA(AssertHighestBit(Zero, _), phaseSummand);
// check that the input is less than modulus
AssertLessThanPhaseLE(modulus, phaseSummand);
}
for (i in 0 .. Length(multiplier!) - 1)
{
let summand = (ExpMod(2, i, modulus) * constMultiplier) % modulus;
Controlled ModularIncrementPhaseLE([(multiplier!)[i]], (summand, modulus, phaseSummand));
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Let us denote modulus by N and constMultiplier by a
/// then this operation implements a unitary defined by the following map on
/// computational basis:
/// |y⟩ ↦ |a⋅y (mod N) ⟩, for all y between 0 and N - 1
///
/// # Input
/// ## constMultiplier
/// Constant by which multiplier is being multiplied. Must be co-prime to modulus.
/// ## modulus
/// The multiplication operation is performed modulo `modulus`
/// ## multiplier
/// The number being multiplied by a constant.
/// This is an array of qubits representing integer in little-endian bit order.
///
/// # Remarks
/// - For the circuit diagram and explanation see Figure 7 on [Page 8
/// of arXiv:quant-ph/0205095v3](https://arxiv.org/pdf/quant-ph/0205095v3.pdf#page=8)
/// - This operation corresponds to Uₐ in
/// [arXiv:quant-ph/0205095v3](https://arxiv.org/pdf/quant-ph/0205095v3.pdf)
operation ModularMultiplyByConstantLE (constMultiplier : Int, modulus : Int, multiplier : LittleEndian) : Unit
{
body (...)
{
// Check the preconditions using Microsoft.Quantum.Canon.AssertBoolEqual
AssertBoolEqual(constMultiplier >= 0 && constMultiplier < modulus, true, $"`constMultiplier` must be between 0 and `modulus`");
AssertBoolEqual(modulus <= 2 ^ Length(multiplier!), true, $"`multiplier` must be big enough to fit integers modulo `modulus`");
AssertBoolEqual(IsCoprime(constMultiplier, modulus), true, $"`constMultiplier` and `modulus` must be co-prime");
using (summand = Qubit[Length(multiplier!)])
{
// recall that newly allocated qubits are all in 0 state
// and therefore summandLE encodes 0.
let summandLE = LittleEndian(summand);
// Let us look at what is the result of operations below assuming
// multiplier is in computational basis and encodes x
// Currently the joint state of multiplier and summandLE is
// |x⟩|0⟩
ModularAddProductLE(constMultiplier, modulus, multiplier, summandLE);
// now the joint state is |x⟩|x⋅a(mod N)⟩
for (i in 0 .. Length(summandLE!) - 1)
{
SWAP((summandLE!)[i], (multiplier!)[i]);
}
// now the joint state is |x⋅a(mod N)⟩|x⟩
let inverseMod = InverseMod(constMultiplier, modulus);
// note that the operation below implements the following map:
// |x⟩|y⟩ ↦ |x⟩|y - a⁻¹⋅x (mod N)⟩
Adjoint ModularAddProductLE(inverseMod, modulus, multiplier, summandLE);
// now the joint state is |x⋅a(mod N)⟩|x - a⁻¹⋅x⋅a (mod N)⟩ = |x⋅a(mod N)⟩|0⟩
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Create an array that contains the same elements as an input array but in reverse
/// order.
@ -19,17 +22,20 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// An array containing the elements `array[Length(array) - 1]` .. `array[0]`.
function Reverse<'T>(array : 'T[]) : 'T[] {
function Reverse<'T> (array : 'T[]) : 'T[]
{
let nElements = Length(array);
mutable newArray = new 'T[nElements];
for (idxElement in 0..nElements - 1) {
set newArray[nElements - idxElement - 1] = array[idxElement];
for (idxElement in 0 .. nElements - 1)
{
set newArray[(nElements - idxElement) - 1] = array[idxElement];
}
return newArray;
}
/// # Summary
/// Creates an array that is equal to an input array except that the first array
/// element is dropped.
@ -44,10 +50,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// An array containing the elements `array[1..Length(array) - 1]`.
function Rest<'T>(array : 'T[]) : 'T[] {
return array[1..Length(array) - 1];
function Rest<'T> (array : 'T[]) : 'T[]
{
return array[1 .. Length(array) - 1];
}
/// # Summary
/// Creates an array that is equal to an input array except that the last array
/// element is dropped.
@ -62,14 +70,18 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// An array containing the elements `array[0..Length(array) - 2]`.
function Most<'T>(array : 'T[]) : 'T[] {
return array[0..Length(array) - 2];
function Most<'T> (array : 'T[]) : 'T[]
{
return array[0 .. Length(array) - 2];
}
function LookupImpl<'T>(array : 'T[], index : Int) : 'T {
function LookupImpl<'T> (array : 'T[], index : Int) : 'T
{
return array[index];
}
/// # Summary
/// Given an array, returns a function which returns elements of that
/// array.
@ -92,10 +104,12 @@ namespace Microsoft.Quantum.Canon {
/// is common, for instance, in the generator representation library,
/// where functions are used to avoid the need to record an entire array
/// in memory.
function LookupFunction<'T>(array : 'T[]) : (Int -> 'T) {
function LookupFunction<'T> (array : 'T[]) : (Int -> 'T)
{
return LookupImpl(array, _);
}
/// # Summary
/// Given two arrays, returns a new array of pairs such that each pair
/// contains an element from each original array.
@ -119,28 +133,34 @@ namespace Microsoft.Quantum.Canon {
///
/// # Example
/// ```Q#
/// let left = [1; 3; 71];
/// let right = [false; true];
/// let pairs = Zip(left, right); // [(1, false); (3, true)]
/// let left = [1, 3, 71];
/// let right = [false, true];
/// let pairs = Zip(left, right); // [(1, false), (3, true)]
/// ```
function Zip<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] {
function Zip<'T, 'U> (left : 'T[], right : 'U[]) : ('T, 'U)[]
{
mutable nElements = 0;
if (Length(left) < Length(right)) {
if (Length(left) < Length(right))
{
set nElements = Length(left);
} else {
}
else
{
set nElements = Length(right);
}
mutable output = new ('T, 'U)[nElements];
for (idxElement in 0..nElements - 1) {
for (idxElement in 0 .. nElements - 1)
{
set output[idxElement] = (left[idxElement], right[idxElement]);
}
return output;
}
/// # Summary
/// Returns the last element of the array.
///
@ -154,11 +174,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The last element of the array.
function Tail<'A> ( array : 'A[] ) : 'A {
AssertBoolEqual(Length(array) > 0, true, "Array must be of the length at least 1" );
function Tail<'A> (array : 'A[]) : 'A
{
AssertBoolEqual(Length(array) > 0, true, $"Array must be of the length at least 1");
return array[Length(array) - 1];
}
/// # Summary
/// Returns the first element of the array.
///
@ -172,11 +194,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The first element of the array.
function Head<'A> ( array : 'A[] ) : 'A {
AssertBoolEqual(Length(array) > 0, true, "Array must be of the length at least 1" );
function Head<'A> (array : 'A[]) : 'A
{
AssertBoolEqual(Length(array) > 0, true, $"Array must be of the length at least 1");
return array[0];
}
/// # Summary
/// Creates an array of given length with all elements equal to given value.
///
@ -188,16 +212,19 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A new array of length `length`, such that every element is `value`.
function ConstantArray<'T>( length : Int, value : 'T ) : 'T[]
function ConstantArray<'T> (length : Int, value : 'T) : 'T[]
{
mutable arr = new 'T[length];
for( i in 0 .. length - 1 )
for (i in 0 .. length - 1)
{
set arr[i] = value;
}
return arr;
}
/// # Summary
/// Returns an array containing the elements of another array,
/// excluding elements at a given list of indices.
@ -221,40 +248,46 @@ namespace Microsoft.Quantum.Canon {
///
/// # Example
/// ```Q#
/// let array = [10; 11; 12; 13; 14; 15];
/// // The following line returns [10; 12; 15].
/// let subarray = Exclude([1; 3; 4], array);
/// let array = [10, 11, 12, 13, 14, 15];
/// // The following line returns [10, 12, 15].
/// let subarray = Exclude([1, 3, 4], array);
/// ```
function Exclude<'T>(remove : Int[], array : 'T[]) : 'T[]
{
let nSliced = Length(remove);
let nElements = Length(array);
//Would be better with sort function
//Or way to add elements to array
mutable arrayKeep = new Int[nElements];
mutable sliced = new 'T[nElements - nSliced];
mutable counter = 0;
for ( idx in 0..nElements - 1) {
set arrayKeep[idx] = idx;
}
for ( idx in 0..nSliced - 1 ) {
set arrayKeep[remove[idx]] = -1;
}
for ( idx in 0..nElements - 1 ) {
if(arrayKeep[idx] >= 0){
set sliced[counter] = array[arrayKeep[idx]];
set counter = counter + 1;
}
}
return sliced;
}
function Exclude<'T> (remove : Int[], array : 'T[]) : 'T[]
{
let nSliced = Length(remove);
let nElements = Length(array);
//Would be better with sort function
//Or way to add elements to array
mutable arrayKeep = new Int[nElements];
mutable sliced = new 'T[nElements - nSliced];
mutable counter = 0;
for (idx in 0 .. nElements - 1)
{
set arrayKeep[idx] = idx;
}
for (idx in 0 .. nSliced - 1)
{
set arrayKeep[remove[idx]] = -1;
}
for (idx in 0 .. nElements - 1)
{
if (arrayKeep[idx] >= 0)
{
set sliced[counter] = array[arrayKeep[idx]];
set counter = counter + 1;
}
}
return sliced;
}
/// # Summary
/// Returns an array padded at with specified values up to a
/// Returns an array padded at with specified values up to a
/// specified length.
///
/// # Type Parameters
@ -277,28 +310,97 @@ namespace Microsoft.Quantum.Canon {
///
/// # Example
/// ```Q#
/// let array = [10; 11; 12];
/// // The following line returns [10; 12; 15; 2; 2; 2].
/// let array = [10, 11, 12];
/// // The following line returns [10, 12, 15, 2, 2, 2].
/// let output = Pad(-6, array, 2);
/// // The following line returns [2; 2; 2; 10; 12; 15].
/// // The following line returns [2, 2, 2, 10, 12, 15].
/// let output = Pad(6, array, 2);
/// ```
function Pad<'T>(nElementsTotal: Int, defaultElement: 'T, inputArray: 'T[]) : 'T[]
function Pad<'T> (nElementsTotal : Int, defaultElement : 'T, inputArray : 'T[]) : 'T[]
{
let nElementsInitial = Length(inputArray);
let nAbsElementsTotal = AbsI(nElementsTotal);
AssertBoolEqual(nAbsElementsTotal >= nElementsInitial, true, "Specified output array length must be longer than `inputArray` length." );
AssertBoolEqual(nAbsElementsTotal >= nElementsInitial, true, $"Specified output array length must be longer than `inputArray` length.");
let nElementsPad = nAbsElementsTotal - nElementsInitial;
let padArray = ConstantArray(nElementsPad, defaultElement);
if(nElementsTotal >= 0){
if (nElementsTotal >= 0)
{
// Pad at head.
return padArray + inputArray;
}
else{
else
{
// Pad at tail.
return inputArray + padArray;
}
}
/// # Summary
/// Creates an array `arr` of integers enumnerated by start..step..end.
///
/// # Input
/// ## range
/// A `Range` of values `start..step..end` to be converted to an array.
///
/// # Output
/// A new array of integers corresponding to values iterated over by `range`.
///
/// # Example
/// ```Q#
/// // The following returns [1;3;5;7];
/// // let array = IntArrayFromRange(1..2..8);
/// ```
function IntArrayFromRange (range: Range) : Int[] {
let start = RangeStart(range);
let step = RangeStep(range);
let end = RangeEnd(range);
if ((end - start) / step >= 0){
let nTerms = (end - start) / step + 1;
mutable array = new Int[nTerms];
for(idx in 0..nTerms - 1){
set array[idx] = start + idx * step;
}
return array;
}
else {
return new Int[0];
}
}
/// # Summary
/// Splits an array into multiple parts.
///
/// # Input
/// ## nElements
/// Number of elements in each part of array
/// ## arr
/// Input array to be split.
///
/// # Output
/// Multiple arrays where the first array is the first 'nElements[0]' of `arr`
/// and the second array are the next 'nElements[1]' of `arr` etc. The last array
/// will contain all remaining elements.
///
/// # Example
/// ```Q#
/// // The following returns [[1;5];[3];[7]];
/// let (arr1, arr2) = SplitArray([2;1], [1;5;3;7]);
/// ```
function SplitArray<'T>(nElements: Int[], arr: 'T[]) : 'T[][] {
mutable output = new 'T[][Length(nElements)+1];
mutable currIdx = 0;
for(idx in 0..Length(nElements)-1){
if(currIdx + nElements[idx] > Length(arr)){
fail "SplitArray argument out of bounds.";
}
set output[idx] = arr[currIdx..currIdx + nElements[idx]-1];
set currIdx = currIdx + nElements[idx];
}
set output[Length(nElements)] = arr[currIdx..Length(arr)-1];
return output;
}
}

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Asserts that a classical floating point variable has the expected value up to a given
/// absolute tolerance.
@ -17,13 +18,17 @@ namespace Microsoft.Quantum.Canon {
///
/// ## tolerance
/// Absolute tolerance on the difference between actual and expected.
function AssertAlmostEqualTol(actual : Double, expected : Double, tolerance : Double) : () {
function AssertAlmostEqualTol (actual : Double, expected : Double, tolerance : Double) : Unit
{
let delta = actual - expected;
if (delta > tolerance || delta < -tolerance) {
fail $"Assertion failed.\n\tExpected: {expected}.\n\tActual: {actual}";
if (delta > tolerance || delta < -tolerance)
{
fail $"Assertion failed. Expected: '{expected}'. Actual: '{actual}'";
}
}
/// # Summary
/// Asserts that a classical floating point variable has the expected value up to a
/// small tolerance of 1e-10.
@ -38,10 +43,12 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// This is equivalent to <xref:microsoft.quantum.canon.assertalmostequaltol> with
/// hardcoded tolerance=1e-10.
function AssertAlmostEqual(actual : Double, expected : Double) : () {
AssertAlmostEqualTol(actual, expected, 1e-10);
function AssertAlmostEqual (actual : Double, expected : Double) : Unit
{
AssertAlmostEqualTol(actual, expected, 1E-10);
}
/// # Summary
/// Asserts that a classical Int variable has the expected value.
///
@ -54,13 +61,15 @@ namespace Microsoft.Quantum.Canon {
///
/// ## message
/// Failure message string to be used when the assertion is triggered.
function AssertIntEqual ( actual : Int, expected : Int, message : String ) : () {
if ( actual != expected )
function AssertIntEqual (actual : Int, expected : Int, message : String) : Unit
{
if (actual != expected)
{
fail message;
}
}
/// # Summary
/// Asserts that a classical Bool variable has the expected value.
///
@ -73,12 +82,15 @@ namespace Microsoft.Quantum.Canon {
///
/// ## message
/// Failure message string to be used when the assertion is triggered.
function AssertBoolEqual ( actual : Bool, expected : Bool, message : String ) : () {
if( actual != expected ) {
function AssertBoolEqual (actual : Bool, expected : Bool, message : String) : Unit
{
if (actual != expected)
{
fail message;
}
}
/// # Summary
/// Asserts that a classical Result variable has the expected value.
///
@ -91,12 +103,15 @@ namespace Microsoft.Quantum.Canon {
///
/// ## message
/// Failure message string to be used when the assertion is triggered.
function AssertResultEqual ( actual : Result, expected : Result, message : String ) : () {
if( actual != expected ) {
function AssertResultEqual (actual : Result, expected : Result, message : String) : Unit
{
if (actual != expected)
{
fail message;
}
}
/// # Summary
/// Asserts that two arrays of boolean values are equal.
///
@ -107,16 +122,24 @@ namespace Microsoft.Quantum.Canon {
/// The array that is expected from a test case of interest.
/// ## message
/// A message to be printed if the arrays are not equal.
function AssertBoolArrayEqual ( actual : Bool[], expected : Bool[], message : String ) : () {
let n = Length(actual);
if (n != Length(expected)) {
function AssertBoolArrayEqual (actual : Bool[], expected : Bool[], message : String) : Unit
{
let n = Length(actual);
if (n != Length(expected))
{
fail message;
}
for (idx in 0..(n-1)) {
if( actual[idx] != expected[idx] ) {
for (idx in 0 .. n - 1)
{
if (actual[idx] != expected[idx])
{
fail message;
}
}
}
}

Просмотреть файл

@ -1,23 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Given an $n$-qubit quantum state $\ket{\psi}=\sum^{2^n-1}_{j=0}\alpha_j \ket{j}$,
/// asserts that the probability $|\alpha_j|^2$ of the state $\ket{j}$ indexed by $j$
/// Given an $n$-qubit quantum state $\ket{\psi}=\sum^{2^n-1}_{j=0}\alpha_j \ket{j}$,
/// asserts that the probability $|\alpha_j|^2$ of the state $\ket{j}$ indexed by $j$
/// has the expected value.
///
/// # Input
/// ## stateIndex
/// The index $j$ of the state $\ket{j}$ represented by a `LittleEndian`
/// The index $j$ of the state $\ket{j}$ represented by a `LittleEndian`
/// register.
///
/// ## expected
@ -30,36 +30,37 @@ namespace Microsoft.Quantum.Canon
/// Absolute tolerance on the difference between actual and expected.
///
/// # Example
/// Suppose that the `qubits` register encodes a 3-qubit quantum state
/// Suppose that the `qubits` register encodes a 3-qubit quantum state
/// $\ket{\psi}=\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{6}$ in little-endian format.
/// This means that the number states $\ket{0}\equiv\ket{0}\ket{0}\ket{0}$
/// and $\ket{6}\equiv\ket{0}\ket{1}\ket{1}$. Then the following asserts succeed:
/// - `AssertProbInt(0,0.125,qubits,10e-10);`
/// - `AssertProbInt(6,0.875,qubits,10e-10);`
operation AssertProbInt(stateIndex: Int, expected: Double, qubits: LittleEndian, tolerance: Double) : () {
body{
let nQubits = Length(qubits);
let bits = BoolArrFromPositiveInt(stateIndex, nQubits);
using(flag = Qubit[1]){
(ControlledOnBitString(bits, X))(qubits, flag[0]);
AssertProb([PauliZ], flag, One, expected, $"AssertProbInt failed on stateIndex {stateIndex}, expected probability {expected}.", tolerance);
//Uncompute flag qubit.
(ControlledOnBitString(bits, X))(qubits, flag[0]);
ResetAll(flag);
}
operation AssertProbInt (stateIndex : Int, expected : Double, qubits : LittleEndian, tolerance : Double) : Unit
{
let nQubits = Length(qubits!);
let bits = BoolArrFromPositiveInt(stateIndex, nQubits);
using (flag = Qubit[1])
{
(ControlledOnBitString(bits, X))(qubits!, flag[0]);
AssertProb([PauliZ], flag, One, expected, $"AssertProbInt failed on stateIndex {stateIndex}, expected probability {expected}.", tolerance);
//Uncompute flag qubit.
(ControlledOnBitString(bits, X))(qubits!, flag[0]);
ResetAll(flag);
}
}
/// # Summary
/// Given an $n$-qubit quantum state $\ket{\psi}=\sum^{2^n-1}_{j=0}\alpha_j \ket{j}$,
/// asserts that the probability $|\alpha_j|^2$ of the state $\ket{j}$ indexed by $j$
/// Given an $n$-qubit quantum state $\ket{\psi}=\sum^{2^n-1}_{j=0}\alpha_j \ket{j}$,
/// asserts that the probability $|\alpha_j|^2$ of the state $\ket{j}$ indexed by $j$
/// has the expected value.
///
/// # Input
/// ## stateIndex
/// The index $j$ of the state $\ket{j}$ represented by a `BigEndian`
/// The index $j$ of the state $\ket{j}$ represented by a `BigEndian`
/// register.
///
/// ## expected
@ -72,21 +73,21 @@ namespace Microsoft.Quantum.Canon
/// Absolute tolerance on the difference between actual and expected.
///
/// # Example
/// Suppose that the `qubits` register encodes a 3-qubit quantum state
/// Suppose that the `qubits` register encodes a 3-qubit quantum state
/// $\ket{\psi}=\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{6}$ in big-endian format.
/// This means that the number states $\ket{0}\equiv\ket{0}\ket{0}\ket{0}$
/// and $\ket{6}\equiv\ket{1}\ket{1}\ket{0}$. Then the following asserts succeed:
/// - `AssertProbIntBE(0,0.125,qubits,10e-10);`
/// - `AssertProbIntBE(6,0.875,qubits,10e-10);`
operation AssertProbIntBE(stateIndex: Int, prob: Double, qubits: BigEndian, tolerance: Double) : () {
body{
let qubitsLE = LittleEndian(Reverse(qubits));
AssertProbInt(stateIndex, prob, qubitsLE, tolerance);
}
operation AssertProbIntBE (stateIndex : Int, prob : Double, qubits : BigEndian, tolerance : Double) : Unit
{
let qubitsLE = LittleEndian(Reverse(qubits!));
AssertProbInt(stateIndex, prob, qubitsLE, tolerance);
}
/// # Summary
/// Asserts that the phase $\phi$ of an equal superposition quantum state
/// Asserts that the phase $\phi$ of an equal superposition quantum state
/// that may be expressed as
/// $\frac{e^{i t}}{\sqrt{2}}(e^{i\phi}\ket{0} + e^{-i\phi}\ket{1})$
/// for some arbitrary real t has the expected value.
@ -111,13 +112,15 @@ namespace Microsoft.Quantum.Canon
///
/// `qubit` is in state $\ket{\psi}=e^{-i 2.2}\sqrt{1/2}\ket{0}+e^{i 0.2}\sqrt{1/2}\ket{1}$;
/// - `AssertPhase(-1.2,qubit,10e-10);`
operation AssertPhase(expected: Double, qubit: Qubit, tolerance: Double) : () {
body{
let expectedProbX = Cos(expected)*Cos(expected);
let expectedProbY = Sin(-1.0*expected+PI()/4.0)*Sin(-1.0*expected+PI()/4.0);
AssertProb([PauliZ], [qubit], Zero, 0.5, $"AssertPhase failed. Was not given a uniform superposition.", tolerance);
AssertProb([PauliY], [qubit], Zero, expectedProbY, $"AssertPhase failed. PauliY Zero basis did not give probability {expectedProbY}.", tolerance);
AssertProb([PauliX], [qubit], Zero, expectedProbX, $"AssertPhase failed. PauliX Zero basis did not give probability {expectedProbX}.", tolerance);
}
operation AssertPhase (expected : Double, qubit : Qubit, tolerance : Double) : Unit
{
let exptectedProbX = Cos(expected) * Cos(expected);
let exptectedProbY = Sin(-1.0 * expected + PI() / 4.0) * Sin(-1.0 * expected + PI() / 4.0);
AssertProb([PauliZ], [qubit], Zero, 0.5, $"AssertPhase failed. Was not given a uniform superposition.", tolerance);
AssertProb([PauliY], [qubit], Zero, exptectedProbY, $"AssertPhase failed. PauliY Zero basis did not give probability {exptectedProbY}.", tolerance);
AssertProb([PauliX], [qubit], Zero, exptectedProbX, $"AssertPhase failed. PauliX Zero basis did not give probability {exptectedProbX}.", tolerance);
}
}

24
Canon/src/Canon.csproj Normal file
Просмотреть файл

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Microsoft.Quantum.Canon</AssemblyName>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<NoWarn>0162</NoWarn>
<RunQDocGen>True</RunQDocGen>
<Authors>Microsoft</Authors>
<Description>Microsoft's Quantum Core Libraries.</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageReleaseNotes>See: https://docs.microsoft.com/en-us/quantum/relnotes/</PackageReleaseNotes>
<PackageLicenseUrl>https://github.com/Microsoft/Quantum/raw/master/LICENSE.txt</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/Microsoft/Quantum</PackageProjectUrl>
<PackageIconUrl>https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png</PackageIconUrl>
<PackageTags>Quantum Q# Qsharp</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,17 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Combinators for constructing multiply controlled versions of operations
///////////////////////////////////////////////////////////////////////////////////////////////
/// # Summary
/// The signature type of CCNOT gate.
newtype CCNOTop = (( Qubit, Qubit, Qubit ) => () : Adjoint );
newtype CCNOTop = ((Qubit, Qubit, Qubit) => Unit : Adjoint);
/// # Summary
/// Applies a multiply controlled version of singly controlled
/// operation.
@ -43,30 +45,34 @@ namespace Microsoft.Quantum.Canon
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyMultiControlledCA
operation ApplyMultiControlledC (
singlyControlledOp : ( Qubit[] => () ),
ccnot : CCNOTop,
controls : Qubit[],
targets : Qubit[] ) : () {
body {
AssertBoolEqual(
Length(controls) >= 1, true,
"Length of controls must be at least 1" );
if( Length(controls) == 1 ) {
singlyControlledOp( controls + targets );
} else {
using( ancillas = Qubit[ Length(controls) - 1 ] ) {
operation ApplyMultiControlledC (singlyControlledOp : (Qubit[] => Unit), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(Length(controls) >= 1, true, $"Length of controls must be at least 1");
if (Length(controls) == 1)
{
singlyControlledOp(controls + targets);
}
else
{
using (ancillas = Qubit[Length(controls) - 1])
{
AndLadder(ccnot, controls, ancillas);
singlyControlledOp( [Tail(ancillas)] + targets );
(Adjoint AndLadder)(ccnot, controls, ancillas);
singlyControlledOp([Tail(ancillas)] + targets);
Adjoint AndLadder(ccnot, controls, ancillas);
}
}
}
controlled( extraControls ) {
ApplyMultiControlledC(singlyControlledOp,ccnot,extraControls+controls,targets);
controlled (extraControls, ...)
{
ApplyMultiControlledC(singlyControlledOp, ccnot, extraControls + controls, targets);
}
}
/// # Summary
/// Applies a multiply controlled version of singly controlled
/// operation.
@ -99,32 +105,38 @@ namespace Microsoft.Quantum.Canon
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyMultiControlledC
operation ApplyMultiControlledCA (
singlyControlledOp : ( Qubit[] => () : Adjoint ),
ccnot : CCNOTop,
controls : Qubit[],
targets : Qubit[] ) : () {
body {
AssertBoolEqual(
Length(controls) >= 1, true,
"Length of controls must be at least 1" );
if( Length(controls) == 1 ) {
singlyControlledOp( controls + targets );
} else {
using( ancillas = Qubit[ Length(controls) - 1 ] ) {
operation ApplyMultiControlledCA (singlyControlledOp : (Qubit[] => Unit : Adjoint), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(Length(controls) >= 1, true, $"Length of controls must be at least 1");
if (Length(controls) == 1)
{
singlyControlledOp(controls + targets);
}
else
{
using (ancillas = Qubit[Length(controls) - 1])
{
AndLadder(ccnot, controls, ancillas);
singlyControlledOp( [Tail(ancillas)] + targets );
(Adjoint AndLadder)(ccnot, controls, ancillas);
singlyControlledOp([Tail(ancillas)] + targets);
Adjoint AndLadder(ccnot, controls, ancillas);
}
}
}
adjoint auto
controlled( extraControls ) {
ApplyMultiControlledCA(singlyControlledOp,ccnot,extraControls+controls,targets);
adjoint invert;
controlled (extraControls, ...)
{
ApplyMultiControlledCA(singlyControlledOp, ccnot, extraControls + controls, targets);
}
controlled adjoint auto
controlled adjoint invert;
}
/// # Summary
/// Applies a unitary given by the following map on computational basis vectors:
/// $$
@ -160,17 +172,23 @@ namespace Microsoft.Quantum.Canon
/// - Used as a part of <xref:microsoft.quantum.canon.applymulticontrolledc>
/// and <xref:microsoft.quantum.canon.applymulticontrolledca>.
/// - For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang.
operation AndLadder ( ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : () {
body{
AssertBoolEqual( Length(controls) == Length(targets) + 1, true,
"Length(controls) must be equal to Length(target) + 1" );
AssertBoolEqual( Length(controls) >= 2, true,
"The operation is not defined for less than 2 controls" );
ccnot(controls[0], controls[1], targets[0]);
for ( k in 1 .. Length(targets)- 1 ) {
ccnot(controls[k + 1],targets[k - 1],targets[k]);
operation AndLadder (ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(Length(controls) == Length(targets) + 1, true, $"Length(controls) must be equal to Length(target) + 1");
AssertBoolEqual(Length(controls) >= 2, true, $"The operation is not defined for less than 2 controls");
ccnot!(controls[0], controls[1], targets[0]);
for (k in 1 .. Length(targets) - 1)
{
ccnot!(controls[k + 1], targets[k - 1], targets[k]);
}
}
adjoint auto
adjoint invert;
}
}

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Applies a single-qubit operation to each element in a register.
/// The modifier 'CA' indicates that the single-qubit operation is controllable
@ -30,19 +31,22 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEach
operation ApplyToEachCA<'T>(singleElementOperation : ('T => () : Adjoint, Controlled), register : 'T[]) : ()
operation ApplyToEachCA<'T> (singleElementOperation : ('T => Unit : Adjoint, Controlled), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..(Length(register) - 1)) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(register[idxQubit]);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Applies a single-qubit operation to each element in a register.
/// The modifier 'A' indicates that the single-qubit operation is adjointable.
@ -68,17 +72,20 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEach
operation ApplyToEachA<'T>(singleElementOperation : ('T => ():Adjoint), register : 'T[]) : ()
operation ApplyToEachA<'T> (singleElementOperation : ('T => Unit : Adjoint), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..(Length(register) - 1)) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(register[idxQubit]);
}
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Applies a single-qubit operation to each element in a register.
/// The modifier 'C' indicates that the single-qubit operation is controllable.
@ -104,17 +111,20 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEach
operation ApplyToEachC<'T>(singleElementOperation : ('T => ():Controlled), register : 'T[]) : ()
operation ApplyToEachC<'T> (singleElementOperation : ('T => Unit : Controlled), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..(Length(register) - 1)) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(register[idxQubit]);
}
}
controlled auto
controlled distribute;
}
/// # Summary
/// Applies a single-qubit operation to each element in a register.
///
@ -141,13 +151,14 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.ApplyToEachC
/// - Microsoft.Quantum.Canon.ApplyToEachA
/// - Microsoft.Quantum.Canon.ApplyToEachCA
operation ApplyToEach<'T>(singleElementOperation : ('T => ()), register : 'T[]) : ()
operation ApplyToEach<'T> (singleElementOperation : ('T => Unit), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..(Length(register) - 1)) {
singleElementOperation(register[idxQubit]);
}
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(register[idxQubit]);
}
}
}

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Applies a single-qubit operation to each indexed element in a register.
///
@ -15,22 +16,22 @@ namespace Microsoft.Quantum.Canon {
///
/// # Type Parameters
/// ## 'T
/// The target on which each of the operations acts.
/// The target on which each of the operations acts.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEach
/// - Microsoft.Quantum.Canon.ApplyToEachIndexA
/// - Microsoft.Quantum.Canon.ApplyToEachIndexC
/// - Microsoft.Quantum.Canon.ApplyToEachIndexCA
operation ApplyToEachIndex<'T>(singleElementOperation : ((Int, 'T) => ()), register : 'T[]) : ()
operation ApplyToEachIndex<'T> (singleElementOperation : ((Int, 'T) => Unit), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..Length(register) - 1) {
singleElementOperation(idxQubit, register[idxQubit]);
}
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(idxQubit, register[idxQubit]);
}
}
/// # Summary
/// Applies a single-qubit operation to each indexed element in a register.
/// The modifier 'C' indicates that the single-qubit operation is controllable.
@ -43,21 +44,24 @@ namespace Microsoft.Quantum.Canon {
///
/// # Type Parameters
/// ## 'T
/// The target on which each of the operations acts.
/// The target on which each of the operations acts.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEachIndex
operation ApplyToEachIndexC<'T>(singleElementOperation : ((Int, 'T) => () : Controlled), register : 'T[]) : ()
operation ApplyToEachIndexC<'T> (singleElementOperation : ((Int, 'T) => Unit : Controlled), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..Length(register) - 1) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(idxQubit, register[idxQubit]);
}
}
controlled auto
controlled distribute;
}
/// # Summary
/// Applies a single-qubit operation to each indexed element in a register.
/// The modifier 'A' indicates that the single-qubit operation is adjointable.
@ -70,21 +74,24 @@ namespace Microsoft.Quantum.Canon {
///
/// # Type Parameters
/// ## 'T
/// The target on which each of the operations acts.
/// The target on which each of the operations acts.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEachIndex
operation ApplyToEachIndexA<'T>(singleElementOperation : ((Int, 'T) => () : Adjoint), register : 'T[]) : ()
operation ApplyToEachIndexA<'T> (singleElementOperation : ((Int, 'T) => Unit : Adjoint), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..Length(register) - 1) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(idxQubit, register[idxQubit]);
}
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Applies a single-qubit operation to each indexed element in a register.
/// The modifier 'CA' indicates that the single-qubit operation is adjointable
@ -98,21 +105,25 @@ namespace Microsoft.Quantum.Canon {
///
/// # Type Parameters
/// ## 'T
/// The target on which each of the operations acts.
/// The target on which each of the operations acts.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToEachIndex
operation ApplyToEachIndexCA<'T>(singleElementOperation : ((Int, 'T) => () : Adjoint,Controlled), register : 'T[]) : ()
operation ApplyToEachIndexCA<'T> (singleElementOperation : ((Int, 'T) => Unit : Adjoint, Controlled), register : 'T[]) : Unit
{
body {
for (idxQubit in 0..Length(register) - 1) {
body (...)
{
for (idxQubit in 0 .. Length(register) - 1)
{
singleElementOperation(idxQubit, register[idxQubit]);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,99 +1,120 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
// # Overview
// Variants of the operation that applies given one, two and three qubit
// # Overview
// Variants of the operation that applies given one, two and three qubit
// operation to the first one, two and three qubits of a register
/// # Summary
/// Applies operation op to the first qubit in the register.
/// # Input
/// ## op
/// An operation to be applied to the first qubit
/// ## register
/// ## register
/// Qubit array to the first qubit of which the operation is applied
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirstqubita"
/// - @"microsoft.quantum.canon.applytofirstqubitc"
/// - @"microsoft.quantum.canon.applytofirstqubitca"
operation ApplyToFirstQubit( op : (Qubit => ()), register : Qubit[] ) : () {
body {
if (Length(register) == 0) {
fail "Must have at least one qubit to act on.";
}
op(register[0]);
operation ApplyToFirstQubit (op : (Qubit => Unit), register : Qubit[]) : Unit
{
if (Length(register) == 0)
{
fail $"Must have at least one qubit to act on.";
}
op(register[0]);
}
/// # Summary
/// Applies operation op to the first qubit in the register.
/// The modifier 'A' indicates that the operation is adjointable.
/// The modifier 'A' indicates that the operation is adjointable.
/// # Input
/// ## op
/// An operation to be applied to the first qubit
/// ## register
/// ## register
/// Qubit array to the first qubit of which the operation is applied
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirstqubit"
operation ApplyToFirstQubitA( op : (Qubit => () : Adjoint), register : Qubit[] ) : () {
body {
if (Length(register) == 0) {
fail "Must have at least one qubit to act on.";
operation ApplyToFirstQubitA (op : (Qubit => Unit : Adjoint), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) == 0)
{
fail $"Must have at least one qubit to act on.";
}
op(register[0]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Applies operation op to the first qubit in the register.
/// The modifier 'C' indicates that the operation is controllable.
/// # Input
/// ## op
/// An operation to be applied to the first qubit
/// ## register
/// ## register
/// Qubit array to the first qubit of which the operation is applied
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirstqubit"
operation ApplyToFirstQubitC( op : (Qubit => () : Controlled), register : Qubit[] ) : () {
body {
if (Length(register) == 0) {
fail "Must have at least one qubit to act on.";
operation ApplyToFirstQubitC (op : (Qubit => Unit : Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) == 0)
{
fail $"Must have at least one qubit to act on.";
}
op(register[0]);
}
controlled auto
controlled distribute;
}
/// # Summary
/// Applies operation op to the first qubit in the register.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
/// # Input
/// ## op
/// An operation to be applied to the first qubit
/// ## register
/// ## register
/// Qubit array to the first qubit of which the operation is applied
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirstqubit"
operation ApplyToFirstQubitCA( op : (Qubit => () : Adjoint, Controlled), register : Qubit[] ) : () {
body {
if (Length(register) == 0) {
fail "Must have at least one qubit to act on.";
operation ApplyToFirstQubitCA (op : (Qubit => Unit : Adjoint, Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) == 0)
{
fail $"Must have at least one qubit to act on.";
}
op(register[0]);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Applies operation `op` to the first two qubits in the register.
///
@ -113,15 +134,17 @@ namespace Microsoft.Quantum.Canon {
/// - @"microsoft.quantum.canon.applytofirsttwoqubitsa"
/// - @"microsoft.quantum.canon.applytofirsttwoqubitsc"
/// - @"microsoft.quantum.canon.applytofirsttwoqubitsca"
operation ApplyToFirstTwoQubits( op : ((Qubit,Qubit) => ()), register : Qubit[] ) : () {
body {
if (Length(register) < 2) {
fail "Must have at least two qubits to act on.";
}
op(register[0],register[1]);
operation ApplyToFirstTwoQubits (op : ((Qubit, Qubit) => Unit), register : Qubit[]) : Unit
{
if (Length(register) < 2)
{
fail $"Must have at least two qubits to act on.";
}
op(register[0], register[1]);
}
/// # Summary
/// Applies operation `op` to the first two qubits in the register.
/// The modifier 'A' indicates that the operation is adjointable.
@ -140,16 +163,21 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirsttwoqubits"
operation ApplyToFirstTwoQubitsA( op : ((Qubit,Qubit) => () : Adjoint ), register : Qubit[] ) : () {
body {
if (Length(register) < 2) {
fail "Must have at least two qubits to act on.";
operation ApplyToFirstTwoQubitsA (op : ((Qubit, Qubit) => Unit : Adjoint), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 2)
{
fail $"Must have at least two qubits to act on.";
}
op(register[0],register[1]);
op(register[0], register[1]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Applies operation `op` to the first two qubits in the register.
@ -169,19 +197,25 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirsttwoqubits"
operation ApplyToFirstTwoQubitsC( op : ((Qubit,Qubit) => () : Controlled ), register : Qubit[] ) : () {
body {
if (Length(register) < 2) {
fail "Must have at least two qubits to act on.";
operation ApplyToFirstTwoQubitsC (op : ((Qubit, Qubit) => Unit : Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 2)
{
fail $"Must have at least two qubits to act on.";
}
op(register[0],register[1]);
op(register[0], register[1]);
}
controlled auto
controlled distribute;
}
/// # Summary
/// Applies operation `op` to the first two qubits in the register.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
///
/// # Input
/// ## op
@ -197,24 +231,30 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytofirsttwoqubits"
operation ApplyToFirstTwoQubitsCA( op : ((Qubit,Qubit) => () : Adjoint, Controlled ), register : Qubit[] ) : () {
body {
if (Length(register) < 2) {
fail "Must have at least two qubits to act on.";
operation ApplyToFirstTwoQubitsCA (op : ((Qubit, Qubit) => Unit : Adjoint, Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 2)
{
fail $"Must have at least two qubits to act on.";
}
op(register[0],register[1]);
op(register[0], register[1]);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Applies operation `op` to the first three qubits in the register.
/// # Input
/// ## op
/// An operation to be applied to the first three qubits
/// ## register
/// ## register
/// Qubit array to the first three qubits of which the operation is applied.
///
/// # Remarks
@ -226,22 +266,24 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubitsC
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubitsA
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubitsCA
operation ApplyToFirstThreeQubits( op : ((Qubit,Qubit,Qubit) => ()), register : Qubit[] ) : () {
body {
if (Length(register) < 3) {
fail "Must have at least three qubits to act on.";
}
op(register[0],register[1],register[2]);
operation ApplyToFirstThreeQubits (op : ((Qubit, Qubit, Qubit) => Unit), register : Qubit[]) : Unit
{
if (Length(register) < 3)
{
fail $"Must have at least three qubits to act on.";
}
op(register[0], register[1], register[2]);
}
/// # Summary
/// Applies operation `op` to the first three qubits in the register.
/// The modifier 'A' indicates that the operation is adjointable.
/// The modifier 'A' indicates that the operation is adjointable.
/// # Input
/// ## op
/// An operation to be applied to the first three qubits
/// ## register
/// ## register
/// Qubit array to the first three qubits of which the operation is applied.
///
/// # Remarks
@ -252,23 +294,29 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubits
operation ApplyToFirstThreeQubitsA( op : ((Qubit,Qubit,Qubit) => () : Adjoint), register : Qubit[] ) : () {
body {
if (Length(register) < 3) {
fail "Must have at least three qubits to act on.";
operation ApplyToFirstThreeQubitsA (op : ((Qubit, Qubit, Qubit) => Unit : Adjoint), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 3)
{
fail $"Must have at least three qubits to act on.";
}
op(register[0],register[1],register[2]);
op(register[0], register[1], register[2]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Applies operation `op` to the first three qubits in the register.
/// The modifier 'C' indicates that the operation is controllable.
/// The modifier 'C' indicates that the operation is controllable.
/// # Input
/// ## op
/// An operation to be applied to the first three qubits
/// ## register
/// ## register
/// Qubit array to the first three qubits of which the operation is applied.
///
/// # Remarks
@ -279,23 +327,29 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubits
operation ApplyToFirstThreeQubitsC( op : ((Qubit,Qubit,Qubit) => () : Controlled), register : Qubit[] ) : () {
body {
if (Length(register) < 3) {
fail "Must have at least three qubits to act on.";
operation ApplyToFirstThreeQubitsC (op : ((Qubit, Qubit, Qubit) => Unit : Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 3)
{
fail $"Must have at least three qubits to act on.";
}
op(register[0],register[1],register[2]);
op(register[0], register[1], register[2]);
}
controlled auto
controlled distribute;
}
/// # Summary
/// Applies operation `op` to the first three qubits in the register.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
/// # Input
/// ## op
/// An operation to be applied to the first three qubits
/// ## register
/// ## register
/// Qubit array to the first three qubits of which the operation is applied.
///
/// # Remarks
@ -306,15 +360,23 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyToFirstThreeQubits
operation ApplyToFirstThreeQubitsCA( op : ((Qubit,Qubit,Qubit) => () : Adjoint, Controlled), register : Qubit[] ) : () {
body {
if (Length(register) < 3) {
fail "Must have at least three qubits to act on.";
operation ApplyToFirstThreeQubitsCA (op : ((Qubit, Qubit, Qubit) => Unit : Adjoint, Controlled), register : Qubit[]) : Unit
{
body (...)
{
if (Length(register) < 3)
{
fail $"Must have at least three qubits to act on.";
}
op(register[0],register[1],register[2]);
op(register[0], register[1], register[2]);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -0,0 +1,123 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Applies a pair of operations to a given partition of a register into two parts.
///
/// # Input
/// ## op
/// The pair of operations to be applied to the given partition.
/// ## numberOfQubitsToFirstArgument
/// Number of qubits from target to put into the first part of the partition.
/// The remaining qubits constitute the second part of the partition.
/// ## target
/// A register of qubits that are being partitioned and operated on by the
/// given two operation.
///
/// # See Also
/// - @"microsoft.quantum.canon.applytopartitiona"
/// - @"microsoft.quantum.canon.applytopartitionc"
/// - @"microsoft.quantum.canon.applytopartitionca"
operation ApplyToPartition (op : ((Qubit[], Qubit[]) => Unit), numberOfQubitsToFirstArgument : Int, target : Qubit[]) : Unit
{
AssertBoolEqual(numberOfQubitsToFirstArgument >= 0, true, $"numberOfQubitsToFirstArgument must be non-negative");
AssertBoolEqual(Length(target) >= numberOfQubitsToFirstArgument, true, $"Length(target) must greater or equal to numberOfQubitsToFirstArgument");
op(target[0 .. numberOfQubitsToFirstArgument - 1], target[numberOfQubitsToFirstArgument .. Length(target) - 1]);
}
/// # Summary
/// Applies a pair of operations to a given partition of a register into two parts.
/// The modifier 'A' indicates that the operation is adjointable.
///
/// # Input
/// ## op
/// The pair of operations to be applied to the given partition.
/// ## numberOfQubitsToFirstArgument
/// Number of qubits from target to put into the first part of the partition.
/// The remaining qubits constitute the second part of the partition.
/// ## target
/// A register of qubits that are being partitioned and operated on by the
/// given two operation.
///
/// # See Also
/// - @"microsoft.quantum.canon.applytopartition"
operation ApplyToPartitionA (op : ((Qubit[], Qubit[]) => Unit : Adjoint), numberOfQubitsToFirstArgument : Int, target : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(numberOfQubitsToFirstArgument >= 0, true, $"numberOfQubitsToFirstArgument must be non-negative");
AssertBoolEqual(Length(target) >= numberOfQubitsToFirstArgument, true, $"Length(target) must greater or equal to numberOfQubitsToFirstArgument");
op(target[0 .. numberOfQubitsToFirstArgument - 1], target[numberOfQubitsToFirstArgument .. Length(target) - 1]);
}
adjoint invert;
}
/// # Summary
/// Applies a pair of operations to a given partition of a register into two parts.
/// The modifier 'C' indicates that the operation is controllable.
///
/// # Input
/// ## op
/// The pair of operations to be applied to the given partition.
/// ## numberOfQubitsToFirstArgument
/// Number of qubits from target to put into the first part of the partition.
/// The remaining qubits constitute the second part of the partition.
/// ## target
/// A register of qubits that are being partitioned and operated on by the
/// given two operation.
///
/// # See Also
/// - @"microsoft.quantum.canon.applytopartition"
operation ApplyToPartitionC (op : ((Qubit[], Qubit[]) => Unit : Controlled), numberOfQubitsToFirstArgument : Int, target : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(numberOfQubitsToFirstArgument >= 0, true, $"numberOfQubitsToFirstArgument must be non-negative");
AssertBoolEqual(Length(target) >= numberOfQubitsToFirstArgument, true, $"Length(target) must greater or equal to numberOfQubitsToFirstArgument");
op(target[0 .. numberOfQubitsToFirstArgument - 1], target[numberOfQubitsToFirstArgument .. Length(target) - 1]);
}
controlled distribute;
}
/// # Summary
/// Applies a pair of operations to a given partition of a register into two parts.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
///
/// # Input
/// ## op
/// The pair of operations to be applied to the given partition.
/// ## numberOfQubitsToFirstArgument
/// Number of qubits from target to put into the first part of the partition.
/// The remaining qubits constitute the second part of the partition.
/// ## target
/// A register of qubits that are being partitioned and operated on by the
/// given two operation.
///
/// # See Also
/// - @"microsoft.quantum.canon.applytopartition"
operation ApplyToPartitionCA (op : ((Qubit[], Qubit[]) => Unit : Controlled, Adjoint), numberOfQubitsToFirstArgument : Int, target : Qubit[]) : Unit
{
body (...)
{
AssertBoolEqual(numberOfQubitsToFirstArgument >= 0, true, $"numberOfQubitsToFirstArgument must be non-negative");
AssertBoolEqual(Length(target) >= numberOfQubitsToFirstArgument, true, $"Length(target) must greater or equal to numberOfQubitsToFirstArgument");
op(target[0 .. numberOfQubitsToFirstArgument - 1], target[numberOfQubitsToFirstArgument .. Length(target) - 1]);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,20 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # See Also
/// - Microsoft.Quantum.Canon.Bind
operation BindImpl<'T>(operations : ('T => ())[], target : 'T) : () {
body {
for (idxOperation in 0..Length(operations) - 1) {
let op = operations[idxOperation];
op(target);
}
operation BindImpl<'T> (operations : ('T => Unit)[], target : 'T) : Unit
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = operations[idxOperation];
op(target);
}
}
/// # Summary
/// Given an array of operations acting on a single input,
/// produces a new operation that
@ -29,13 +31,13 @@ namespace Microsoft.Quantum.Canon {
/// on its input.
///
/// # Type Parameters
/// ## 'T
/// ## 'T
/// The target on which each of the operations in the array act.
///
/// # Example
/// The following are equivalent:
/// ```Q#
/// let bound = Bind([U; V]);
/// let bound = Bind([U, V]);
/// bound(x);
///
/// U(x); V(x);
@ -45,29 +47,38 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.BindC
/// - Microsoft.Quantum.Canon.BindA
/// - Microsoft.Quantum.Canon.BindCA
function Bind<'T>(operations : ('T => ())[]) : ('T => ()) {
function Bind<'T> (operations : ('T => Unit)[]) : ('T => Unit)
{
return BindImpl(operations, _);
}
/// # See Also
/// - Microsoft.Quantum.Canon.BindA
operation BindAImpl<'T>(operations : ('T => () : Adjoint)[], target : 'T) : () {
body {
for (idxOperation in 0..Length(operations) - 1) {
operation BindAImpl<'T> (operations : ('T => Unit : Adjoint)[], target : 'T) : Unit
{
body (...)
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = operations[idxOperation];
op(target);
}
}
adjoint {
adjoint (...)
{
// TODO: replace with an implementation based on Reversed : 'T[] -> 'T[]
// and AdjointAll : ('T => () : Adjointable)[] -> ('T => () : Adjointable).
for (idxOperation in Length(operations) - 1..-1..0) {
let op = (Adjoint operations[idxOperation]);
for (idxOperation in Length(operations) - 1 .. -1 .. 0)
{
let op = Adjoint operations[idxOperation];
op(target);
}
}
}
/// # Summary
/// Given an array of operations acting on a single input,
/// produces a new operation that
@ -89,7 +100,7 @@ namespace Microsoft.Quantum.Canon {
/// # Example
/// The following are equivalent:
/// ```Q#
/// let bound = Bind([U; V]);
/// let bound = Bind([U, V]);
/// bound(x);
///
/// U(x); V(x);
@ -97,28 +108,36 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.Bind
function BindA<'T>(operations : ('T => () : Adjoint)[]) : ('T => () : Adjoint) {
function BindA<'T> (operations : ('T => Unit : Adjoint)[]) : ('T => Unit : Adjoint)
{
return BindAImpl(operations, _);
}
/// # See Also
/// - Microsoft.Quantum.Canon.BindC
operation BindCImpl<'T>(operations : ('T => () : Controlled)[], target : 'T) : () {
body {
for (idxOperation in 0..Length(operations) - 1) {
operation BindCImpl<'T> (operations : ('T => Unit : Controlled)[], target : 'T) : Unit
{
body (...)
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = operations[idxOperation];
op(target);
}
}
controlled (controls) {
for (idxOperation in 0..Length(operations) - 1) {
let op = (Controlled operations[idxOperation]);
controlled (controls, ...)
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = Controlled operations[idxOperation];
op(controls, target);
}
}
}
/// # Summary
/// Given an array of operations acting on a single input,
/// produces a new operation that
@ -140,7 +159,7 @@ namespace Microsoft.Quantum.Canon {
/// # Example
/// The following are equivalent:
/// ```Q#
/// let bound = Bind([U; V]);
/// let bound = Bind([U, V]);
/// bound(x);
///
/// U(x); V(x);
@ -148,41 +167,54 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.Bind
function BindC<'T>(operations : ('T => () : Controlled)[]) : ('T => () : Controlled) {
function BindC<'T> (operations : ('T => Unit : Controlled)[]) : ('T => Unit : Controlled)
{
return BindCImpl(operations, _);
}
/// # See Also
/// - Microsoft.Quantum.Canon.BindCA
operation BindCAImpl<'T>(operations : ('T => () : Adjoint, Controlled)[], target : 'T) : () {
body {
for (idxOperation in 0..Length(operations) - 1) {
operation BindCAImpl<'T> (operations : ('T => Unit : Adjoint, Controlled)[], target : 'T) : Unit
{
body (...)
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = operations[idxOperation];
op(target);
}
}
adjoint {
for (idxOperation in Length(operations) - 1..-1..0) {
let op = (Adjoint operations[idxOperation]);
adjoint (...)
{
for (idxOperation in Length(operations) - 1 .. -1 .. 0)
{
let op = Adjoint operations[idxOperation];
op(target);
}
}
controlled (controls) {
for (idxOperation in 0..Length(operations) - 1) {
let op = (Controlled operations[idxOperation]);
controlled (controls, ...)
{
for (idxOperation in 0 .. Length(operations) - 1)
{
let op = Controlled operations[idxOperation];
op(controls, target);
}
}
controlled adjoint (controls) {
for (idxOperation in Length(operations) - 1..-1..0) {
let op = (Controlled Adjoint operations[idxOperation]);
controlled adjoint (controls, ...)
{
for (idxOperation in Length(operations) - 1 .. -1 .. 0)
{
let op = Controlled (Adjoint operations[idxOperation]);
op(controls, target);
}
}
}
/// # Summary
/// Given an array of operations acting on a single input,
/// produces a new operation that
@ -205,7 +237,7 @@ namespace Microsoft.Quantum.Canon {
/// # Example
/// The following are equivalent:
/// ```Q#
/// let bound = Bind([U; V]);
/// let bound = Bind([U, V]);
/// bound(x);
///
/// U(x); V(x);
@ -213,8 +245,11 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.Bind
function BindCA<'T>(operations : ('T => () : Adjoint, Controlled)[]) : ('T => () : Adjoint, Controlled) {
function BindCA<'T> (operations : ('T => Unit : Adjoint, Controlled)[]) : ('T => Unit : Adjoint, Controlled)
{
return BindCAImpl(operations, _);
}
}
}

Просмотреть файл

@ -2,129 +2,139 @@
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// if `bit` is true. If false, nothing happens to the `target`.
///
/// # Input
/// ## op
/// An operation to be conditionally applied.
/// ## bit
/// ## bit
/// a boolean that controls whether op is applied or not.
/// ## target
/// ## target
/// The input to which the operation is applied.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyIfC
/// - Microsoft.Quantum.Canon.ApplyIfA
/// - Microsoft.Quantum.Canon.ApplyIfCA
operation ApplyIf<'T>( op : ('T => ()), bit : Bool, target : 'T) : ()
operation ApplyIf<'T> (op : ('T => Unit), bit : Bool, target : 'T) : Unit
{
body{
if (bit) {
if (bit)
{
op(target);
}
}
}
/// # Summary
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// if `bit` is true. If false, nothing happens to the `target`.
/// The modifier 'C' indicates that the operation is controllable.
///
/// # Input
/// ## op
/// An operation to be conditionally applied.
/// ## bit
/// ## bit
/// a boolean that controls whether op is applied or not.
/// ## target
/// ## target
/// The input to which the operation is applied.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyIf
operation ApplyIfC<'T>( op : ('T => () : Controlled), bit : Bool, target : 'T) : ()
operation ApplyIfC<'T> (op : ('T => Unit : Controlled), bit : Bool, target : 'T) : Unit
{
body{
if (bit) {
op(target);
body (...)
{
if (bit)
{
op(target);
}
}
controlled auto
controlled distribute;
}
/// # Summary
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// if `bit` is true. If false, nothing happens to the `target`.
/// The modifier 'A' indicates that the operation is adjointable.
/// The modifier 'A' indicates that the operation is adjointable.
///
/// # Input
/// ## op
/// An operation to be conditionally applied.
/// ## bit
/// ## bit
/// a boolean that controls whether op is applied or not.
/// ## target
/// ## target
/// The input to which the operation is applied.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyIf
operation ApplyIfA<'T>( op : ('T => () : Adjoint), bit : Bool, target : 'T) : ()
operation ApplyIfA<'T> (op : ('T => Unit : Adjoint), bit : Bool, target : 'T) : Unit
{
body{
if (bit) {
op(target);
body (...)
{
if (bit)
{
op(target);
}
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// Given an operation `op` and a bit value `bit`, applies `op` to the `target`
/// if `bit` is true. If false, nothing happens to the `target`.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
///
/// # Input
/// ## op
/// An operation to be conditionally applied.
/// ## bit
/// ## bit
/// a boolean that controls whether op is applied or not.
/// ## target
/// ## target
/// The input to which the operation is applied.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyIf
operation ApplyIfCA<'T>( op : ('T => () : Controlled, Adjoint), bit : Bool, target : 'T) : ()
operation ApplyIfCA<'T> (op : ('T => Unit : Controlled, Adjoint), bit : Bool, target : 'T) : Unit
{
body{
if (bit) {
op(target);
body (...)
{
if (bit)
{
op(target);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Given an operation op, returns a new operation which
/// applies the op if a classical control bit is true. If false, nothing happens.
@ -134,21 +144,22 @@ namespace Microsoft.Quantum.Canon {
/// An operation to be conditionally applied.
///
/// # Output
/// A new operation which is op if the classical control bit is true.
/// A new operation which is op if the classical control bit is true.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ControlledC
/// - Microsoft.Quantum.Canon.ControlledA
/// - Microsoft.Quantum.Canon.ControlledCA
function CControlled<'T>( op : ('T => ())) : ((Bool, 'T) => ())
function CControlled<'T> (op : ('T => Unit)) : ((Bool, 'T) => Unit)
{
return ApplyIf(op, _, _);
}
/// # Summary
/// Given an operation op, returns a new operation which
/// applies the op if a classical control bit is true. If false, nothing happens.
@ -159,42 +170,44 @@ namespace Microsoft.Quantum.Canon {
/// An operation to be conditionally applied.
///
/// # Output
/// A new operation which is op if the classical control bit is true.
/// A new operation which is op if the classical control bit is true.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.Controlled
function CControlledC<'T>( op : ('T => () : Controlled)) : ((Bool, 'T) => () : Controlled)
function CControlledC<'T> (op : ('T => Unit : Controlled)) : ((Bool, 'T) => Unit : Controlled)
{
return ApplyIfC(op, _, _);
}
/// # Summary
/// Given an operation op, returns a new operation which
/// applies the op if a classical control bit is true. If false, nothing happens.
/// The modifier 'A' indicates that the operation is adjointable.
/// The modifier 'A' indicates that the operation is adjointable.
///
/// # Input
/// ## op
/// An operation to be conditionally applied.
///
/// # Output
/// A new operation which is op if the classical control bit is true.
/// A new operation which is op if the classical control bit is true.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.Controlled
function CControlledA<'T>( op : ('T => () : Adjoint)) : ((Bool, 'T) => () : Adjoint)
function CControlledA<'T> (op : ('T => Unit : Adjoint)) : ((Bool, 'T) => Unit : Adjoint)
{
return ApplyIfA(op, _, _);
}
/// # Summary
/// Given an operation op, returns a new operation which
/// applies the op if a classical control bit is true. If false, nothing happens.
@ -205,17 +218,19 @@ namespace Microsoft.Quantum.Canon {
/// An operation to be conditionally applied.
///
/// # Output
/// A new operation which is op if the classical control bit is true.
/// A new operation which is op if the classical control bit is true.
///
/// # Type Parameters
/// ## 'T
/// The input type of the operation to be conditionally applied.
/// ## 'T
/// The input type of the operation to be conditionally applied.
///
/// # See Also
/// - Microsoft.Quantum.Canon.Controlled
function CControlledCA<'T>( op : ('T => (): Controlled, Adjoint)) : ((Bool, 'T) => (): Controlled, Adjoint)
function CControlledCA<'T> (op : ('T => Unit : Controlled, Adjoint)) : ((Bool, 'T) => Unit : Controlled, Adjoint)
{
return ApplyIfCA(op, _, _);
}
}

Просмотреть файл

@ -1,12 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
function ComposeImpl<'T, 'U, 'V>(outer : ('U -> 'V), inner : ('T -> 'U), target : 'T) : 'V {
namespace Microsoft.Quantum.Canon
{
function ComposeImpl<'T, 'U, 'V> (outer : ('U -> 'V), inner : ('T -> 'U), target : 'T) : 'V
{
return outer(inner(target));
}
/// # Summary
/// Given two functions $f$ and $g$, returns a new function representing
/// $f \circ g$.
@ -28,8 +32,11 @@ namespace Microsoft.Quantum.Canon {
/// of the second function to be applied.
/// ## 'V
/// The output type of the second function to be applied.
function Compose<'T, 'U, 'V>(outer : ('U -> 'V), inner : ('T -> 'U)): ('T -> 'V) {
function Compose<'T, 'U, 'V> (outer : ('U -> 'V), inner : ('T -> 'U)) : ('T -> 'V)
{
return ComposeImpl(outer, inner, _);
}
}

Просмотреть файл

@ -1,13 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
function CurryOpImpl<'T, 'U>(op : (('T, 'U) => ()), arg1 : 'T) : ('U => ()) {
namespace Microsoft.Quantum.Canon
{
function CurryOpImpl<'T, 'U> (op : (('T, 'U) => Unit), arg1 : 'T) : ('U => Unit)
{
return op(arg1, _);
}
/// # Summary
/// Given an operation with two inputs, applies Curry's isomorphism
/// $f(x, y) \equiv f(x)(y)$ to return an operation of one input which
@ -23,10 +26,10 @@ namespace Microsoft.Quantum.Canon {
/// original operation's input.
///
/// # Type Parameters
/// ## 'T
/// The type of the first component of a function defined on pairs.
/// ## 'T
/// The type of the first component of a function defined on pairs.
/// ## 'U
/// The type of the second component of a function defined on pairs.
/// The type of the second component of a function defined on pairs.
///
/// # Remarks
/// The following are equivalent:
@ -37,17 +40,19 @@ namespace Microsoft.Quantum.Canon {
/// let partial = curried(x);
/// partial(y);
/// ```
function CurryOp<'T, 'U>(op : (('T, 'U) => ())) : ('T -> ('U => ())) {
function CurryOp<'T, 'U> (op : (('T, 'U) => Unit)) : ('T -> ('U => Unit))
{
return CurryOpImpl(op, _);
}
operation UncurryOpImpl<'T, 'U>(curriedOp : ('T -> ('U => ())), first : 'T, second : 'U) : () {
body {
let innerOp = curriedOp(first);
innerOp(second);
}
operation UncurryOpImpl<'T, 'U> (curriedOp : ('T -> ('U => Unit)), first : 'T, second : 'U) : Unit
{
let innerOp = curriedOp(first);
innerOp(second);
}
/// # Summary
/// Given a function which returns operations,
/// returns a new operation which takes both inputs
@ -62,7 +67,7 @@ namespace Microsoft.Quantum.Canon {
/// to `(curriedOp(t))(u)`.
///
/// # Type Parameters
/// ## 'T
/// ## 'T
/// The type of the first argument of a curried function.
/// ## 'U
/// The type of the second argument of a curried function.
@ -70,19 +75,24 @@ namespace Microsoft.Quantum.Canon {
/// - @"microsoft.quantum.canon.uncurryopc"
/// - @"microsoft.quantum.canon.uncurryopa"
/// - @"microsoft.quantum.canon.uncurryopca"
function UncurryOp<'T, 'U>(curriedOp : ('T -> ('U => ()))) : (('T, 'U) => ()) {
function UncurryOp<'T, 'U> (curriedOp : ('T -> ('U => Unit))) : (('T, 'U) => Unit)
{
return UncurryOpImpl(curriedOp, _, _);
}
operation UncurryOpCImpl<'T, 'U>(curriedOp : ('T -> ('U => () : Controlled)), first : 'T, second : 'U) : () {
body {
operation UncurryOpCImpl<'T, 'U> (curriedOp : ('T -> ('U => Unit : Controlled)), first : 'T, second : 'U) : Unit
{
body (...)
{
let innerOp = curriedOp(first);
innerOp(second);
}
controlled auto
controlled distribute;
}
/// # Summary
/// Given a function which returns operations,
/// returns a new operation which takes both inputs
@ -98,26 +108,31 @@ namespace Microsoft.Quantum.Canon {
/// to `(curriedOp(t))(u)`.
///
/// # Type Parameters
/// ## 'T
/// ## 'T
/// The type of the first argument of a curried function.
/// ## 'U
/// The type of the second argument of a curried function.
///
/// # See Also
/// - @"microsoft.quantum.canon.uncurryop"
function UncurryOpC<'T, 'U>(curriedOp : ('T -> ('U => () : Controlled))) : (('T, 'U) => () : Controlled) {
function UncurryOpC<'T, 'U> (curriedOp : ('T -> ('U => Unit : Controlled))) : (('T, 'U) => Unit : Controlled)
{
return UncurryOpCImpl(curriedOp, _, _);
}
operation UncurryOpAImpl<'T, 'U>(curriedOp : ('T -> ('U => () : Adjoint)), first : 'T, second : 'U) : () {
body {
operation UncurryOpAImpl<'T, 'U> (curriedOp : ('T -> ('U => Unit : Adjoint)), first : 'T, second : 'U) : Unit
{
body (...)
{
let innerOp = curriedOp(first);
innerOp(second);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Given a function which returns operations,
/// returns a new operation which takes both inputs
@ -133,28 +148,33 @@ namespace Microsoft.Quantum.Canon {
/// to `(curriedOp(t))(u)`.
///
/// # Type Parameters
/// ## 'T
/// ## 'T
/// The type of the first argument of a curried function.
/// ## 'U
/// The type of the second argument of a curried function.
///
/// # See Also
/// - @"microsoft.quantum.canon.uncurryop"
function UncurryOpA<'T, 'U>(curriedOp : ('T -> ('U => () : Adjoint))) : (('T, 'U) => () : Adjoint) {
function UncurryOpA<'T, 'U> (curriedOp : ('T -> ('U => Unit : Adjoint))) : (('T, 'U) => Unit : Adjoint)
{
return UncurryOpAImpl(curriedOp, _, _);
}
operation UncurryOpCAImpl<'T, 'U>(curriedOp : ('T -> ('U => () : Controlled, Adjoint)), first : 'T, second : 'U) : () {
body {
operation UncurryOpCAImpl<'T, 'U> (curriedOp : ('T -> ('U => Unit : Controlled, Adjoint)), first : 'T, second : 'U) : Unit
{
body (...)
{
let innerOp = curriedOp(first);
innerOp(second);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Given a function which returns operations,
/// returns a new operation which takes both inputs
@ -170,15 +190,18 @@ namespace Microsoft.Quantum.Canon {
/// to `(curriedOp(t))(u)`.
///
/// # Type Parameters
/// ## 'T
/// ## 'T
/// The type of the first argument of a curried function.
/// ## 'U
/// The type of the second argument of a curried function.
///
/// # See Also
/// - @"microsoft.quantum.canon.uncurryop"
function UncurryOpCA<'T, 'U>(curriedOp : ('T -> ('U => () : Controlled, Adjoint))) : (('T, 'U) => () : Controlled, Adjoint) {
function UncurryOpCA<'T, 'U> (curriedOp : ('T -> ('U => Unit : Controlled, Adjoint))) : (('T, 'U) => Unit : Controlled, Adjoint)
{
return UncurryOpCAImpl(curriedOp, _, _);
}
}

Просмотреть файл

@ -1,53 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
operation OperationPowImpl<'T>(oracle : ('T => ()), power : Int, target : 'T) : ()
namespace Microsoft.Quantum.Canon
{
operation OperationPowImpl<'T> (oracle : ('T => Unit), power : Int, target : 'T) : Unit
{
body {
for (idxApplication in 0..power - 1) {
for (idxApplication in 0 .. power - 1)
{
oracle(target);
}
}
operation OperationPowImplC<'T> (oracle : ('T => Unit : Controlled), power : Int, target : 'T) : Unit
{
body (...)
{
for (idxApplication in 0 .. power - 1)
{
oracle(target);
}
}
controlled distribute;
}
operation OperationPowImplC<'T>(oracle : ('T => () : Controlled), power : Int, target : 'T) : ()
operation OperationPowImplA<'T> (oracle : ('T => Unit : Adjoint), power : Int, target : 'T) : Unit
{
body {
for (idxApplication in 0..power - 1) {
body (...)
{
for (idxApplication in 0 .. power - 1)
{
oracle(target);
}
}
controlled auto
adjoint invert;
}
operation OperationPowImplA<'T>(oracle : ('T => () : Adjoint), power : Int, target : 'T) : ()
operation OperationPowImplCA<'T> (oracle : ('T => Unit : Controlled, Adjoint), power : Int, target : 'T) : Unit
{
body {
for (idxApplication in 0..power - 1) {
body (...)
{
for (idxApplication in 0 .. power - 1)
{
oracle(target);
}
}
adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation OperationPowImplCA<'T>(oracle : ('T => () : Controlled, Adjoint), power : Int, target : 'T) : ()
{
body {
for (idxApplication in 0..power - 1) {
oracle(target);
}
}
adjoint auto
controlled auto
controlled adjoint auto
}
/// # Summary
/// Given an operation representing a gate $U$, returns a new operation
/// $U^m$ for a power $m$.
@ -62,18 +72,19 @@ namespace Microsoft.Quantum.Canon {
/// A new operation representing $U^m$, where $m = \texttt{power}$.
///
/// # Type Parameters
/// ## 'T
/// The type of the operation to be powered.
/// ## 'T
/// The type of the operation to be powered.
///
/// # See Also
/// - @"microsoft.quantum.canon.operationpowc"
/// - @"microsoft.quantum.canon.operationpowa"
/// - @"microsoft.quantum.canon.operationpowca"
function OperationPow<'T>(oracle : ('T => ()), power : Int) : ('T => ())
function OperationPow<'T> (oracle : ('T => Unit), power : Int) : ('T => Unit)
{
return OperationPowImpl(oracle, power, _);
}
/// # Summary
/// Given an operation representing a gate $U$, returns a new operation
/// $U^m$ for a power $m$.
@ -89,20 +100,21 @@ namespace Microsoft.Quantum.Canon {
/// A new operation representing $U^m$, where $m = \texttt{power}$.
///
/// # Type Parameters
/// ## 'T
/// The type of the operation to be powered.
/// ## 'T
/// The type of the operation to be powered.
///
/// # See Also
/// - @"microsoft.quantum.canon.operationpow"
function OperationPowC<'T>(oracle : ('T => () : Controlled), power : Int) : ('T => () : Controlled)
function OperationPowC<'T> (oracle : ('T => Unit : Controlled), power : Int) : ('T => Unit : Controlled)
{
return OperationPowImplC(oracle, power, _);
}
/// # Summary
/// Given an operation representing a gate $U$, returns a new operation
/// $U^m$ for a power $m$.
/// The modifier 'A' indicates that the operation is adjointable.
/// The modifier 'A' indicates that the operation is adjointable.
///
/// # Input
/// ## oracle
@ -114,16 +126,17 @@ namespace Microsoft.Quantum.Canon {
/// A new operation representing $U^m$, where $m = \texttt{power}$.
///
/// # Type Parameters
/// ## 'T
/// The type of the operation to be powered.
/// ## 'T
/// The type of the operation to be powered.
///
/// # See Also
/// - @"microsoft.quantum.canon.operationpow"
function OperationPowA<'T>(oracle : ('T => () : Adjoint), power : Int) : ('T => () : Adjoint)
function OperationPowA<'T> (oracle : ('T => Unit : Adjoint), power : Int) : ('T => Unit : Adjoint)
{
return OperationPowImplA(oracle, power, _);
}
/// # Summary
/// Given an operation representing a gate $U$, returns a new operation
/// $U^m$ for a power $m$.
@ -139,14 +152,16 @@ namespace Microsoft.Quantum.Canon {
/// A new operation representing $U^m$, where $m = \texttt{power}$.
///
/// # Type Parameters
/// ## 'T
/// The type of the operation to be powered.
/// ## 'T
/// The type of the operation to be powered.
///
/// # See Also
/// - @"microsoft.quantum.canon.operationpow"
function OperationPowCA<'T>(oracle : ('T => () : Controlled, Adjoint), power : Int) : ('T => () : Controlled, Adjoint)
function OperationPowCA<'T> (oracle : ('T => Unit : Controlled, Adjoint), power : Int) : ('T => Unit : Controlled, Adjoint)
{
return OperationPowImplCA(oracle, power, _);
}
}

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Applies an operation to a subregister of a register, with qubits
/// specified by an array of their indices.
@ -21,7 +22,7 @@ namespace Microsoft.Quantum.Canon {
/// Create three qubit state $\frac{1}{\sqrt{2}}\ket{0}\_2(\ket{0}\_1\ket{0}_3+\ket{1}\_1\ket{1}_3)$:
/// ```qsharp
/// using (register = Qubit[3]) {
/// ApplyToSubregister(Exp([PauliX;PauliY;],PI() / 4.0,_), [1;3], register);
/// ApplyToSubregister(Exp([PauliX,PauliY],PI() / 4.0,_), [1,3], register);
/// }
/// ```
///
@ -29,13 +30,13 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.ApplyToSubregisterA
/// - Microsoft.Quantum.Canon.ApplyToSubregisterC
/// - Microsoft.Quantum.Canon.ApplyToSubregisterCA
operation ApplyToSubregister(op : (Qubit[] => ()), idxs : Int[], target : Qubit[]) : () {
body {
let subregister = Subarray(idxs, target);
op(subregister);
}
operation ApplyToSubregister (op : (Qubit[] => Unit), idxs : Int[], target : Qubit[]) : Unit
{
let subregister = Subarray(idxs, target);
op(subregister);
}
/// # Summary
/// Applies an operation to a subregister of a register, with qubits
/// specified by an array of their indices.
@ -51,15 +52,20 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytosubregister"
operation ApplyToSubregisterA(op : (Qubit[] => () : Adjoint), idxs : Int[], target : Qubit[]) : () {
body {
operation ApplyToSubregisterA (op : (Qubit[] => Unit : Adjoint), idxs : Int[], target : Qubit[]) : Unit
{
body (...)
{
ApplyToSubregister(op, idxs, target);
}
adjoint {
adjoint (...)
{
ApplyToSubregister(Adjoint op, idxs, target);
}
}
/// # Summary
/// Applies an operation to a subregister of a register, with qubits
/// specified by an array of their indices.
@ -75,16 +81,21 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytosubregister"
operation ApplyToSubregisterC(op : (Qubit[] => () : Controlled), idxs : Int[], target : Qubit[]) : () {
body {
operation ApplyToSubregisterC (op : (Qubit[] => Unit : Controlled), idxs : Int[], target : Qubit[]) : Unit
{
body (...)
{
ApplyToSubregister(op, idxs, target);
}
controlled (controls) {
let cop = (Controlled op);
controlled (controls, ...)
{
let cop = Controlled op;
ApplyToSubregister(cop(controls, _), idxs, target);
}
}
/// # Summary
/// Applies an operation to a subregister of a register, with qubits
/// specified by an array of their indices.
@ -100,23 +111,32 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.applytosubregister"
operation ApplyToSubregisterCA(op : (Qubit[] => () : Controlled, Adjoint), idxs : Int[], target : Qubit[]) : () {
body {
operation ApplyToSubregisterCA (op : (Qubit[] => Unit : Controlled, Adjoint), idxs : Int[], target : Qubit[]) : Unit
{
body (...)
{
ApplyToSubregister(op, idxs, target);
}
adjoint {
adjoint (...)
{
ApplyToSubregister(Adjoint op, idxs, target);
}
controlled (controls) {
let cop = (Controlled op);
controlled (controls, ...)
{
let cop = Controlled op;
ApplyToSubregister(cop(controls, _), idxs, target);
}
controlled adjoint (controls) {
let cop = (Controlled Adjoint op);
controlled adjoint (controls, ...)
{
let cop = Controlled (Adjoint op);
ApplyToSubregister(cop(controls, _), idxs, target);
}
}
/// # Summary
/// Restricts an operation to an array of indices of a register, i.e., a subregister.
///
@ -132,10 +152,12 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.RestrictToSubregisterA
/// - Microsoft.Quantum.Canon.RestrictToSubregisterC
/// - Microsoft.Quantum.Canon.RestrictToSubregisterCA
function RestrictToSubregister(op : (Qubit[] => ()), idxs : Int[]) : (Qubit[] => ()) {
function RestrictToSubregister (op : (Qubit[] => Unit), idxs : Int[]) : (Qubit[] => Unit)
{
return ApplyToSubregister(op, idxs, _);
}
/// # Summary
/// Restricts an operation to an array of indices of a register, i.e., a subregister.
/// The modifier 'A' indicates that the operation is adjointable.
@ -150,10 +172,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.RestrictToSubregister
function RestrictToSubregisterA(op : (Qubit[] => () : Adjoint), idxs : Int[]) : (Qubit[] => () : Adjoint) {
function RestrictToSubregisterA (op : (Qubit[] => Unit : Adjoint), idxs : Int[]) : (Qubit[] => Unit : Adjoint)
{
return ApplyToSubregisterA(op, idxs, _);
}
/// # Summary
/// Restricts an operation to an array of indices of a register, i.e., a subregister.
/// The modifier 'C' indicates that the operation is controllable.
@ -168,10 +192,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.RestrictToSubregister
function RestrictToSubregisterC(op : (Qubit[] => () : Controlled), idxs : Int[]) : (Qubit[] => () : Controlled) {
function RestrictToSubregisterC (op : (Qubit[] => Unit : Controlled), idxs : Int[]) : (Qubit[] => Unit : Controlled)
{
return ApplyToSubregisterC(op, idxs, _);
}
/// # Summary
/// Restricts an operation to an array of indices of a register, i.e., a subregister.
/// The modifier 'CA' indicates that the operation is controllable and adjointable.
@ -186,8 +212,11 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.RestrictToSubregister
function RestrictToSubregisterCA(op : (Qubit[] => () : Adjoint, Controlled), idxs : Int[]) : (Qubit[] => () : Adjoint, Controlled) {
function RestrictToSubregisterCA (op : (Qubit[] => Unit : Adjoint, Controlled), idxs : Int[]) : (Qubit[] => Unit : Adjoint, Controlled)
{
return ApplyToSubregisterCA(op, idxs, _);
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Given operations implementing operators $U$ and $V$, performs the
/// operation $UVU^{\dagger}$ on a target. That is, this operation
@ -33,15 +36,14 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.WithC
/// - Microsoft.Quantum.Canon.WithA
/// - Microsoft.Quantum.Canon.WithCA
operation With<'T>(outerOperation : ('T => ():Adjoint), innerOperation : ('T => ()), target : 'T) : ()
operation With<'T> (outerOperation : ('T => Unit : Adjoint), innerOperation : ('T => Unit), target : 'T) : Unit
{
body {
outerOperation(target);
innerOperation(target);
(Adjoint(outerOperation))(target);
}
outerOperation(target);
innerOperation(target);
Adjoint outerOperation(target);
}
/// # Summary
/// Given operations implementing operators $U$ and $V$, performs the
/// operation $UVU^{\dagger}$ on a target. That is, this operation
@ -69,17 +71,19 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.With
operation WithA<'T>(outerOperation : ('T => ():Adjoint), innerOperation : ('T => ():Adjoint), target : 'T) : ()
operation WithA<'T> (outerOperation : ('T => Unit : Adjoint), innerOperation : ('T => Unit : Adjoint), target : 'T) : Unit
{
body {
body (...)
{
outerOperation(target);
innerOperation(target);
(Adjoint(outerOperation))(target);
Adjoint outerOperation(target);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Given operations implementing operators $U$ and $V$, performs the
/// operation $UVU^{\dagger}$ on a target. That is, this operation
@ -107,22 +111,25 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.With
operation WithC<'T>(outerOperation : ('T => ():Adjoint), innerOperation : ('T => ():Controlled), target : 'T) : ()
operation WithC<'T> (outerOperation : ('T => Unit : Adjoint), innerOperation : ('T => Unit : Controlled), target : 'T) : Unit
{
body {
body (...)
{
outerOperation(target);
innerOperation(target);
(Adjoint(outerOperation))(target);
Adjoint outerOperation(target);
}
controlled(controlRegister) {
controlled (controlRegister, ...)
{
outerOperation(target);
(Controlled(innerOperation))(controlRegister, target);
(Adjoint(outerOperation))(target);
Controlled innerOperation(controlRegister, target);
Adjoint outerOperation(target);
}
}
/// # Summary
/// # Summary
/// Given operations implementing operators $U$ and $V$, performs the
/// operation $UVU^{\dagger}$ on a target. That is, this operation
/// conjugates $V$ with $U$.
@ -150,21 +157,27 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.With
operation WithCA<'T>(outerOperation : ('T => ():Adjoint), innerOperation : ('T => ():Adjoint,Controlled), target : 'T) : ()
operation WithCA<'T> (outerOperation : ('T => Unit : Adjoint), innerOperation : ('T => Unit : Adjoint, Controlled), target : 'T) : Unit
{
body {
body (...)
{
outerOperation(target);
innerOperation(target);
(Adjoint(outerOperation))(target);
Adjoint outerOperation(target);
}
adjoint auto
controlled(controlRegister) {
adjoint invert;
controlled (controlRegister, ...)
{
outerOperation(target);
(Controlled(innerOperation))(controlRegister, target);
(Adjoint(outerOperation))(target);
Controlled innerOperation(controlRegister, target);
Adjoint outerOperation(target);
}
controlled adjoint auto
controlled adjoint invert;
}
}
}

108
Canon/src/CommonGates.qs Normal file
Просмотреть файл

@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
/// # Summary
/// Applies the controlled-$X$ (CX) gate to a pair of qubits,
/// $$
/// \begin{align}
/// 1 & 0 & 0 & 0 \\\\
/// 0 & 1 & 0 & 0 \\\\
/// 0 & 0 & 0 & 1 \\\\
/// 0 & 0 & 1 & 0
/// \end{align},
/// $$
/// where rows and columns are organized as in the quantum concepts guide.
///
/// # Input
/// ## control
/// Control qubit for the CX gate.
/// ## target
/// Target qubit for the CX gate.
///
/// # Remarks
/// Equivalent to:
/// ```Q#
/// Controlled X([control], target);
/// ```
///
/// Equivalent to:
/// ```Q#
/// CNOT(control, target);
/// ```
operation CX(control : Qubit, target : Qubit) : Unit {
body (...) {
Controlled X([control], target);
}
adjoint self;
controlled distribute;
controlled adjoint self;
}
/// # Summary
/// Applies the controlled-$Y$ (CY) gate to a pair of qubits,
/// $$
/// \begin{align}
/// 1 & 0 & 0 & 0 \\\\
/// 0 & 1 & 0 & 0 \\\\
/// 0 & 0 & 0 & -i \\\\
/// 0 & 0 & i & 0
/// \end{align},
/// $$
/// where rows and columns are organized as in the quantum concepts guide.
///
/// # Input
/// ## control
/// Control qubit for the CY gate.
/// ## target
/// Target qubit for the CY gate.
///
/// # Remarks
/// Equivalent to:
/// ```Q#
/// Controlled Y([control], target);
/// ```
operation CY(control : Qubit, target : Qubit) : Unit {
body (...) {
Controlled Y([control], target);
}
adjoint self;
controlled distribute;
controlled adjoint self;
}
/// # Summary
/// Applies the controlled-$Z$ (CZ) gate to a pair of qubits,
/// $$
/// \begin{align}
/// 1 & 0 & 0 & 0 \\\\
/// 0 & 1 & 0 & 0 \\\\
/// 0 & 0 & 1 & 0 \\\\
/// 0 & 0 & 0 & -1
/// \end{align},
/// $$
/// where rows and columns are organized as in the quantum concepts guide.
///
/// # Input
/// ## control
/// Control qubit for the CZ gate.
/// ## target
/// Target qubit for the CZ gate.
///
/// # Remarks
/// Equivalent to:
/// ```Q#
/// Controlled Z([control], target);
/// ```
operation CZ(control : Qubit, target : Qubit) : Unit {
body (...) {
Controlled Z([control], target);
}
adjoint self;
controlled distribute;
controlled adjoint self;
}
}

Просмотреть файл

@ -1,11 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Represents a single primitive term in the set of all dynamical generators, e.g.
/// Hermitian operators, for which there exists a map from that generator
@ -25,17 +27,16 @@ namespace Microsoft.Quantum.Canon {
/// Using <xref:microsoft.quantum.canon.paulievolutionset>, the operator
/// $\pi X_2 X_5 Y_9$ is represented as:
/// ```qsharp
/// let index = GeneratorIndex(([1; 1; 2], [PI()]), [2; 5; 9]);
/// let index = GeneratorIndex(([1, 1, 2], [PI()]), [2, 5, 9]);
/// ```
///
/// # See Also
/// - @"microsoft.quantum.canon.paulievolutionset"
/// - @"microsoft.quantum.canon.evolutionset"
newtype GeneratorIndex = ((Int[], Double[]), Int[]);
/// # Summary
/// From the view of a GeneratorSystem, a description of a Hamiltonian
// is a collection of GeneratorTerms. We iterate over this
/// collection using a single-index integer, and the size of the
/// collection is assumed to be known.
///
@ -46,22 +47,22 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - @"microsoft.quantum.canon.lookupfunction"
newtype GeneratorSystem = (Int, (Int -> GeneratorIndex));
/// # Summary
/// Represents a time-dependent dynamical generator as a function
/// from time to the value of the dynamical generator at that time.
newtype TimeDependentGeneratorSystem = (Double -> GeneratorSystem);
/// # Summary
/// Represents evolution under a unitary operator.
newtype Unitary = (Qubit[] => () : Adjoint, Controlled);
newtype Unitary = (Qubit[] => Unit : Adjoint, Controlled);
/// # Summary
/// Represents a unitary time-evolution operator. The first parameter is
/// is duration of time-evolution, and the second parameter is the qubit
/// register acted upon by the unitary.
newtype EvolutionUnitary = ((Double, Qubit[]) => () : Adjoint, Controlled);
newtype EvolutionUnitary = ((Double, Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// Represents a set of gates that can be readily implemented and used
/// to implement simulation algorithms. Elements in the set are indexed
@ -71,18 +72,19 @@ namespace Microsoft.Quantum.Canon {
/// which are operations
/// parameterized by a real number representing time
newtype EvolutionSet = (GeneratorIndex -> EvolutionUnitary);
/// # Summary
/// Represents a dynamical generator as a set of simulatable gates and
/// an expansion in terms of that basis.
/// Last parameter for number of terms
newtype EvolutionGenerator = (EvolutionSet, GeneratorSystem);
/// # Summary
/// Represents a time-dependent dynamical generator. The `Double`
/// parameter is a schedule in $[0, 1]$.
newtype EvolutionSchedule = (EvolutionSet, (Double -> GeneratorSystem));
/// # Summary
/// Returns a generator index consistent with the
/// Hamiltonian $H = 0$.
@ -95,10 +97,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// A generator index representing evolution under the Hamiltonian
/// $H = 0$.
function IdentityGeneratorIndex(idxTerm : Int) : GeneratorIndex {
return GeneratorIndex(([0], [0.0]),[0]);
function IdentityGeneratorIndex (idxTerm : Int) : GeneratorIndex
{
return GeneratorIndex(([0], [0.0]), [0]);
}
/// # Summary
/// Returns a generator system consistent with the
/// Hamiltonian $H = 0$.
@ -106,10 +110,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// A generator system representing evolution under the Hamiltonian
/// $H = 0$.
function IdentityGeneratorSystem() : GeneratorSystem {
return GeneratorSystem(0, IdentityGeneratorIndex);
function IdentityGeneratorSystem () : GeneratorSystem
{
return GeneratorSystem(0, IdentityGeneratorIndex);
}
/// # Summary
/// Returns a generator system consistent with the
/// Hamiltonian $H(s) = 0$, where $s$ is a schedule parameter.
@ -122,10 +128,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// A generator system representing evolution under the Hamiltonian
/// $H(s) = 0$ for all $s$.
function _IdentityTimeDependentGeneratorSystem(schedule: Double) : GeneratorSystem {
function _IdentityTimeDependentGeneratorSystem (schedule : Double) : GeneratorSystem
{
return IdentityGeneratorSystem();
}
/// # Summary
/// Returns a time-dependent generator system consistent with the
/// Hamiltonian $H(s) = 0$.
@ -133,10 +141,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// A time dependent generator system representing evolution under the Hamiltonian
/// $H(s) = 0$ for all $s$.
function IdentityTimeDependentGeneratorSystem() : TimeDependentGeneratorSystem {
function IdentityTimeDependentGeneratorSystem () : TimeDependentGeneratorSystem
{
return TimeDependentGeneratorSystem(_IdentityTimeDependentGeneratorSystem);
}
/// # Summary
/// Retrieves the number of terms in a `GeneratorSystem`.
///
@ -149,11 +159,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.generatorsystem"
function GetGeneratorSystemNTerms(generatorSystem : GeneratorSystem) : Int {
let (nTerms, generatorIndexFunction) = generatorSystem;
function GetGeneratorSystemNTerms (generatorSystem : GeneratorSystem) : Int
{
let (nTerms, generatorIndexFunction) = generatorSystem!;
return nTerms;
}
/// # Summary
/// Retrieves the `GeneratorIndex` function in a `GeneratorSystem`.
///
@ -167,13 +179,15 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - @"microsoft.quantum.canon.generatorindex"
/// - @"microsoft.quantum.canon.generatorsystem"
function GetGeneratorSystemFunction(generatorSystem : GeneratorSystem) : (Int -> GeneratorIndex) {
let (nTerms, generatorIndexFunction) = generatorSystem;
function GetGeneratorSystemFunction (generatorSystem : GeneratorSystem) : (Int -> GeneratorIndex)
{
let (nTerms, generatorIndexFunction) = generatorSystem!;
return generatorIndexFunction;
}
// We should be able to do some algebra on representations of the system
// We should be able to do some algebra on representations of the system
/// # Summary
/// Multiplies the coefficient in a `GeneratorIndex`.
///
@ -189,30 +203,34 @@ namespace Microsoft.Quantum.Canon {
///
/// # Example
/// ```qsharp
/// let gen = GeneratorIndex(([1;2;3],[coeff]),[1;2;3);
/// let ((idxPaulis, idxDoubles), idxQubits) = MultiplyGeneratorIndex(multiplier, gen);
/// // idxDoubles[0] == multiplier * coeff;
/// let gen = GeneratorIndex(([1,2,3],[coeff]),[1;2;3);
/// let ((idxPaulis, idxDoubles), idxQubits) = MultiplyGeneratorIndex(multipler, gen);
/// // idxDoubles[0] == multipler * coeff;
/// ```
///
/// # See Also
/// - @"microsoft.quantum.canon.generatorindex"
function MultiplyGeneratorIndex(multiplier: Double, generatorIndex : GeneratorIndex) : GeneratorIndex {
let ((idxTerms, idxDoubles), idxSystems) = generatorIndex;
function MultiplyGeneratorIndex (multiplier : Double, generatorIndex : GeneratorIndex) : GeneratorIndex
{
let ((idxTerms, idxDoubles), idxSystems) = generatorIndex!;
mutable idxDoublesOut = idxDoubles;
set idxDoublesOut[0] = multiplier * idxDoublesOut[0];
return GeneratorIndex((idxTerms, idxDoublesOut), idxSystems);
}
/// # Summary
/// Multiplies the coefficient of all terms in a `GeneratorSystem`.
///
/// # Remarks
/// This is an intermediate step and should not be called.
function _MultiplyGeneratorSystem(multiplier: Double, idxTerm: Int, generatorSystem : GeneratorSystem) : GeneratorIndex {
let (nTerms, generatorIndexFunction) = generatorSystem;
return MultiplyGeneratorIndex(multiplier , generatorIndexFunction(idxTerm));
function _MultiplyGeneratorSystem (multiplier : Double, idxTerm : Int, generatorSystem : GeneratorSystem) : GeneratorIndex
{
let (nTerms, generatorIndexFunction) = generatorSystem!;
return MultiplyGeneratorIndex(multiplier, generatorIndexFunction(idxTerm));
}
/// # Summary
/// Multiplies the coefficient of all terms in a `GeneratorSystem`.
///
@ -228,30 +246,31 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.GeneratorSystem
function MultiplyGeneratorSystem(multiplier: Double, generatorSystem : GeneratorSystem) : GeneratorSystem {
let nTerms = GetGeneratorSystemNTerms(generatorSystem);
function MultiplyGeneratorSystem (multiplier : Double, generatorSystem : GeneratorSystem) : GeneratorSystem
{
let nTerms = GetGeneratorSystemNTerms(generatorSystem);
return GeneratorSystem(nTerms, _MultiplyGeneratorSystem(multiplier, _, generatorSystem));
}
/// # Summary
/// Adds two `GeneratorSystems` to create a new GeneratorSystem.
///
/// # Remarks
/// This is an intermediate step and should not be called.
function _AddGeneratorSystems( idxTerm : Int,
nTermsA : Int,
nTermsB : Int,
generatorIndexFunctionA : (Int -> GeneratorIndex),
generatorIndexFunctionB : (Int -> GeneratorIndex)) : GeneratorIndex {
if(idxTerm < nTermsA){
function _AddGeneratorSystems (idxTerm : Int, nTermsA : Int, nTermsB : Int, generatorIndexFunctionA : (Int -> GeneratorIndex), generatorIndexFunctionB : (Int -> GeneratorIndex)) : GeneratorIndex
{
if (idxTerm < nTermsA)
{
return generatorIndexFunctionA(idxTerm);
}
else{
else
{
return generatorIndexFunctionB(idxTerm - nTermsA);
}
}
/// # Summary
/// Adds two `GeneratorSystems` to create a new GeneratorSystem.
///
@ -267,7 +286,8 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.GeneratorSystem
function AddGeneratorSystems(generatorSystemA: GeneratorSystem, generatorSystemB: GeneratorSystem) : GeneratorSystem {
function AddGeneratorSystems (generatorSystemA : GeneratorSystem, generatorSystemB : GeneratorSystem) : GeneratorSystem
{
let nTermsA = GetGeneratorSystemNTerms(generatorSystemA);
let nTermsB = GetGeneratorSystemNTerms(generatorSystemB);
let generatorIndexFunctionA = GetGeneratorSystemFunction(generatorSystemA);
@ -275,9 +295,10 @@ namespace Microsoft.Quantum.Canon {
let generatorIndexFunction = _AddGeneratorSystems(_, nTermsA, nTermsB, generatorIndexFunctionA, generatorIndexFunctionB);
return GeneratorSystem(nTermsA + nTermsB, generatorIndexFunction);
}
/// Create description of system that interpolates between two GeneratorSystems based on a schedule parameter in [0,1]
///
/// # Summary
/// Linearly interpolates between two `GeneratorSystems` according to a
/// schedule parameter $s\in[0,1]$.
@ -297,15 +318,16 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.GeneratorSystem
function InterpolateGeneratorSystemsImpl(schedule: Double, generatorSystemStart: GeneratorSystem, generatorSystemEnd: GeneratorSystem) : GeneratorSystem
function InterpolateGeneratorSystemsImpl (schedule : Double, generatorSystemStart : GeneratorSystem, generatorSystemEnd : GeneratorSystem) : GeneratorSystem
{
let sysStart = MultiplyGeneratorSystem((1.0 - schedule), generatorSystemStart);
let sysStart = MultiplyGeneratorSystem(1.0 - schedule, generatorSystemStart);
let sysEnd = MultiplyGeneratorSystem(schedule, generatorSystemEnd);
return AddGeneratorSystems(sysStart, sysEnd);
}
}
/// # Summary
/// Returns a `TimeDependentGeneratorSystem` representing the linear
/// Returns a `TimeDependentGeneratorSystem` representing the linear
/// interpolation between two `GeneratorSystems` according to a
/// schedule parameter $s\in[0,1]$.
///
@ -316,16 +338,36 @@ namespace Microsoft.Quantum.Canon {
/// The end `GeneratorSystem`.
///
/// # Output
/// A `TimeDependentGeneratorSystem` representing a system that is the
/// sum of the input generator systems, with weight $(1-s)$ on
/// A `TimeDependentGeneratorSystem` representing a system that is the
/// sum of the input generator systems, with weight $(1-s)$ on
/// `generatorSystemStart` and weight $s$ on `generatorSystemEnd`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.GeneratorSystem
/// - Microsoft.Quantum.Canon.TimeDependentGeneratorSystem
function InterpolateGeneratorSystems(generatorSystemStart: GeneratorSystem, generatorSystemEnd: GeneratorSystem) : TimeDependentGeneratorSystem
function InterpolateGeneratorSystems (generatorSystemStart : GeneratorSystem, generatorSystemEnd : GeneratorSystem) : TimeDependentGeneratorSystem
{
return TimeDependentGeneratorSystem(InterpolateGeneratorSystemsImpl(_, generatorSystemStart, generatorSystemEnd));
}
}
/// # Summary
/// Adds multiple `GeneratorSystems` to create a new GeneratorSystem.
///
/// # Input
/// ## generatorSystems
/// An array of type `GeneratorSystem[]`.
///
/// # Output
/// A `GeneratorSystem` representing a system that is the sum of the
/// input generator systems.
///
/// # See Also
/// - Microsoft.Quantum.Canon.GeneratorSystem
function SumGeneratorSystems(generatorSystems: GeneratorSystem[]) : GeneratorSystem {
return Fold(AddGeneratorSystems, IdentityGeneratorSystem(), generatorSystems);
}
}

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Given a pair, returns its first element.
///
@ -19,11 +20,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The first element of `pair`.
function Fst<'T, 'U>(pair : ('T, 'U)) : 'T {
function Fst<'T, 'U> (pair : ('T, 'U)) : 'T
{
let (fst, snd) = pair;
return fst;
}
/// # Summary
/// Given a pair, returns its second element.
///
@ -39,9 +42,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The second element of `pair`.
function Snd<'T, 'U>(pair : ('T, 'U)) : 'U {
function Snd<'T, 'U> (pair : ('T, 'U)) : 'U
{
let (fst, snd) = pair;
return snd;
}
}

Просмотреть файл

@ -1,14 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// A last-in-first-out stack of `Result` variables.
/// The stack consists of an integer capacity, a stack pointer and a `Result` array.
newtype ResultStack = (Int, Int, Result[]);
newtype ResultStack = (Int, Int, Result[]);
/// # Summary
/// Retrieves the capacity of a <xref:microsoft.quantum.canon.resultstack>.
///
@ -18,11 +20,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The number of elements fitting into the stack.
function StackCapacity(stack : ResultStack) : Int {
let (size, pos, data) = stack;
function StackCapacity (stack : ResultStack) : Int
{
let (size, pos, data) = stack!;
return size;
}
/// # Summary
/// Retrieves the number of elements stored in a
/// <xref:microsoft.quantum.canon.resultstack>.
@ -33,11 +37,13 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The number of elements on the stack.
function StackLength(stack : ResultStack) : Int {
let (size, pos, data) = stack;
function StackLength (stack : ResultStack) : Int
{
let (size, pos, data) = stack!;
return pos;
}
/// # Summary
/// Removes the topmost element from a <xref:microsoft.quantum.canon.resultstack>.
///
@ -48,14 +54,19 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// The `stack` with the top element removed. The new stack has the same capacity as
/// the old one, but its length is reduced by one.
function StackPop(stack : ResultStack) : (ResultStack) {
let (size, pos, data) = stack;
if (pos == 0) {
fail "Cannot pop an empty stack.";
function StackPop (stack : ResultStack) : ResultStack
{
let (size, pos, data) = stack!;
if (pos == 0)
{
fail $"Cannot pop an empty stack.";
}
return ResultStack(size, pos - 1, data);
}
/// # Summary
/// Pushes a new element onto a <xref:microsoft.quantum.canon.resultstack>.
///
@ -68,10 +79,13 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// The `stack` with `datum` added as its new top element. The new stack's length is
/// increased by one.
function StackPush(stack : ResultStack, datum : Result) : ResultStack {
let (size, pos, data) = stack;
if (pos == size) {
fail "Stack is full.";
function StackPush (stack : ResultStack, datum : Result) : ResultStack
{
let (size, pos, data) = stack!;
if (pos == size)
{
fail $"Stack is full.";
}
// FIXME: implies an O(n) copy!
@ -80,10 +94,10 @@ namespace Microsoft.Quantum.Canon {
// See also: https://msdn.microsoft.com/en-us/library/dn467197(v=vs.111).aspx
mutable newData = data;
set newData[pos] = datum;
return ResultStack(size, pos + 1, newData);
}
/// # Summary
/// Retrieves the topmost element of a <xref:microsoft.quantum.canon.resultstack>.
///
@ -93,14 +107,19 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The value stored at the top of `stack`.
function StackPeek(stack : ResultStack) : Result {
let (size, pos, data) = stack;
if (pos == 0) {
fail "Cannot peek at an empty stack.";
function StackPeek (stack : ResultStack) : Result
{
let (size, pos, data) = stack!;
if (pos == 0)
{
fail $"Cannot peek at an empty stack.";
}
return data[pos - 1];
}
/// # Summary
/// Creates a new empty <xref:microsoft.quantum.canon.resultstack> with given capacity.
///
@ -110,8 +129,11 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A new `ResultStack` that has capacity `size` and length 0.
function StackNew(size : Int) : ResultStack {
function StackNew (size : Int) : ResultStack
{
return ResultStack(size, 0, new Result[size]);
}
}

Просмотреть файл

@ -1,16 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
/// # Summary
/// The `Filter` function takes an array and a predicate that is defined
/// for the elements of the array, and returns an array that consists of
/// those elements that satisfy the predicate.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// The `Filter` function takes an array and a predicate that is defined
/// for the elements of the array, and returns an array that consists of
/// those elements that satisfy the predicate.
///
/// # Remarks
/// The function is defined for generic types, i.e., whenever we have
/// an array `'T[]` and a predicate `'T -> Bool` we can filter elements.
/// The function is defined for generic types, i.e., whenever we have
/// an array `'T[]` and a predicate `'T -> Bool` we can filter elements.
///
/// # Type Parameters
/// ## 'T
@ -18,21 +20,29 @@ namespace Microsoft.Quantum.Canon {
///
/// # Input
/// ## predicate
/// A function from `'T' to Boolean that is used to filter elements.
/// A function from `'T' to Boolean that is used to filter elements.
/// ## array
/// An array of elements over `'T`.
///
///
/// # Output
/// An array `'T[]` of elements that satisfy the predicate.
function Filter<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] {
function Filter<'T> (predicate : ('T -> Bool), array : 'T[]) : 'T[]
{
mutable totalFound = 0;
mutable idxArray = new Int[Length(array)];
for (idxElement in 0..Length(array) - 1) {
if predicate(array[idxElement]) {
mutable idxArray = new Int[Length(array)];
for (idxElement in 0 .. Length(array) - 1)
{
if (predicate(array[idxElement]))
{
set idxArray[totalFound] = idxElement;
set totalFound = totalFound + 1;
}
}
return Subarray(idxArray[0..totalFound-1], array);
return Subarray(idxArray[0 .. totalFound - 1], array);
}
}

Просмотреть файл

@ -1,8 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Iterates a function `f` through an array `array`, returning
/// `f(f(f(initialState, array[0]), array[1]), ...)`.
@ -33,12 +35,18 @@ namespace Microsoft.Quantum.Canon {
/// return Fold(Plus, 0.0, xs);
/// }
/// ```
function Fold<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State {
function Fold<'State, 'T> (folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State
{
mutable current = state;
for (idxElement in 0..Length(array) - 1) {
for (idxElement in 0 .. Length(array) - 1)
{
set current = folder(current, array[idxElement]);
}
return current;
}
}

Просмотреть файл

@ -1,18 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
/// # Summary
/// The `ForAll` function takes an array and a predicate that is defined
/// for the elements of the array, and checks if all elements of the
/// array satisfy the predicate.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// The `ForAll` function takes an array and a predicate that is defined
/// for the elements of the array, and checks if all elements of the
/// array satisfy the predicate.
///
/// # Remarks
/// The function is defined for generic types, i.e., whenever we have
/// The function is defined for generic types, i.e., whenever we have
/// an array `'T[]` and a function `predicate: 'T -> Bool` we can produce
/// a `Bool` value that indicates if all elements satisfy `predicate`.
///
/// a `Bool` value that indicates if all elements satisfy `predicate`.
///
/// # Type Parameters
/// ## 'T
/// The type of `array` elements.
@ -22,14 +24,21 @@ namespace Microsoft.Quantum.Canon {
/// A function from `'T` to `Bool` that is used to check elements.
/// ## array
/// An array of elements over `'T`.
///
///
/// # Output
/// A `Bool` value of the AND function of the predicate applied to all elements.
function ForAll<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool {
mutable result = true;
for (idxElement in 0..Length(array) - 1) {
function ForAll<'T> (predicate : ('T -> Bool), array : 'T[]) : Bool
{
mutable result = true;
for (idxElement in 0 .. Length(array) - 1)
{
set result = result && predicate(array[idxElement]);
}
return result;
}
}

Просмотреть файл

@ -1,35 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
/// # Summary
/// The `ForAny` function takes an array and a predicate that is defined
/// for the elements of the array, and checks if at least one element of
/// the array satisfies the predicate.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// The `ForAny` function takes an array and a predicate that is defined
/// for the elements of the array, and checks if at least one element of
/// the array satisfies the predicate.
///
/// # Remarks
/// The function is defined for generic types, i.e., whenever we have
/// The function is defined for generic types, i.e., whenever we have
/// an array `'T[]` and a function `predicate: 'T -> Bool` we can produce
/// a `Bool` value that indicates if some element satisfies `predicate`.
///
/// a `Bool` value that indicates if some element satisfies `predicate`.
///
/// # Type Parameters
/// ## 'T
/// The type of `array` elements.
///
/// # Input
/// ## predicate
/// A function from `'T` to `Bool` that is used to check elements.
/// A function from `'T` to `Bool` that is used to check elements.
/// ## array
/// An array of elements over `'T`.
///
///
/// # Output
/// A `Bool` value of the OR function of the predicate applied to all elements.
function ForAny<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool {
mutable result = false;
for (idxElement in 0..Length(array) - 1) {
function ForAny<'T> (predicate : ('T -> Bool), array : 'T[]) : Bool
{
mutable result = false;
for (idxElement in 0 .. Length(array) - 1)
{
set result = result || predicate(array[idxElement]);
}
return result;
}
}

Просмотреть файл

@ -1,8 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// The `Map` function takes an array and a function that is defined
/// for the elements of the array, and returns a new array that consists
@ -27,14 +29,19 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// An array `'U[]` of elements that are mapped by the `mapper` function.
function Map<'T, 'U>(mapper : ('T -> 'U), array : 'T[]) : 'U[] {
function Map<'T, 'U> (mapper : ('T -> 'U), array : 'T[]) : 'U[]
{
mutable resultArray = new 'U[Length(array)];
for (idxElement in 0..Length(array) - 1) {
for (idxElement in 0 .. Length(array) - 1)
{
set resultArray[idxElement] = mapper(array[idxElement]);
}
return resultArray;
}
/// # Summary
/// The `MapIndex` function takes an array and a function that is defined
/// for the indexed elements of the array, and returns a new array that consists
@ -64,17 +71,24 @@ namespace Microsoft.Quantum.Canon {
/// # Example
/// The following two lines are equivalent:
/// ```Q#
/// let arr = MapIndex(f, [x0; x1; x2]);
/// let arr = [f(0, x0); f(1, x1), f(2; x2)];
/// let arr = MapIndex(f, [x0, x1, x2]);
/// let arr = [f(0, x0), f(1, x1), f(2, x2)];
/// ```
///
/// # See Also
/// - @"microsoft.quantum.canon.map"
function MapIndex<'T, 'U>(mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] {
function MapIndex<'T, 'U> (mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[]
{
mutable resultArray = new 'U[Length(array)];
for (idxElement in 0..Length(array) - 1) {
for (idxElement in 0 .. Length(array) - 1)
{
set resultArray[idxElement] = mapper(idxElement, array[idxElement]);
}
return resultArray;
}
}

Просмотреть файл

@ -1,19 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
/// # Summary
/// Takes an array and a list of locations and
/// produces a new array formed from the elements of the original
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Takes an array and a list of locations and
/// produces a new array formed from the elements of the original
/// array that match the given locations.
///
/// # Remarks
/// The function is defined for generic types, i.e., whenever we have
/// The function is defined for generic types, i.e., whenever we have
/// an array `'T[]` and a list of locations `Int[]` defining the subarray.
/// The construction of the subarray is a based on generating a new, deep
/// copy of the given array as opposed to maintaining references.
/// The construction of the subarray is a based on generating a new, deep
/// copy of the given array as opposed to maintaining references.
///
/// If `Length(indices) < Length(array)`, this function will return a
/// subset of `array`. On the other hand, if `indices` contains repeated
@ -28,20 +29,26 @@ namespace Microsoft.Quantum.Canon {
///
/// # Input
/// ## indices
/// A list of integers that is used to define the subarray.
/// A list of integers that is used to define the subarray.
/// ## array
/// An array of elements over `'T`.
///
/// # Output
/// An array `out` of elements whose indices correspond to the subarray,
/// such that `out[idx] == array[indices[idx]]`.
function Subarray<'T>(indices : Int[], array : 'T[]) : 'T[] {
function Subarray<'T> (indices : Int[], array : 'T[]) : 'T[]
{
let nSliced = Length(indices);
mutable sliced = new 'T[nSliced];
for( idx in 0..nSliced - 1 ) {
for (idx in 0 .. nSliced - 1)
{
set sliced[idx] = array[indices[idx]];
}
return sliced;
}
}

Просмотреть файл

@ -0,0 +1,206 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
/// # Summary
/// Implementation of the first-order Trotter–Suzuki integrator.
///
/// # Type Parameters
/// ## 'T
/// The type which each time step should act upon; typically, either
/// `Qubit[]` or `Qubit`.
///
/// # Input
/// ### nSteps
/// The number of operations to be decomposed into time steps.
/// ### op
/// An operation which accepts an index input (type `Int`) and a time
/// input (type `Double`) and a quantum register (type `'T`) for decomposition.
/// ## stepSize
/// Multiplier on size of each step of the simulation.
/// ## target
/// A quantum register on which the operations act.
///
/// # Remarks
/// ## Example
/// The following are equivalent:
/// ```Q#
/// op(0, deltaT, target);
/// op(1, deltaT, target);
///
/// Trotter1ImplCA((2, op), deltaT, target);
/// ```
operation Trotter1ImplCA<'T> ((nSteps : Int, op : ((Int, Double, 'T) => Unit : Adjoint, Controlled)), stepSize : Double, target : 'T) : Unit
{
body (...)
{
for (idx in 0 .. nSteps - 1)
{
op(idx, stepSize, target);
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implementation of the second-order Trotter–Suzuki integrator.
///
/// # Type Parameters
/// ## 'T
/// The type which each time step should act upon; typically, either
/// `Qubit[]` or `Qubit`.
///
/// # Input
/// ### nSteps
/// The number of operations to be decomposed into time steps.
/// ### op
/// An operation which accepts an index input (type `Int`) and a time
/// input (type `Double`) and a quantum register (type `'T`) for decomposition.
/// ## stepSize
/// Multiplier on size of each step of the simulation.
/// ## target
/// A quantum register on which the operations act.
///
/// # Remarks
/// ## Example
/// The following are equivalent:
/// ```Q#
/// op(0, deltaT / 2.0, target);
/// op(1, deltaT / 2.0, target);
/// op(1, deltaT / 2.0, target);
/// op(0, deltaT / 2.0, target);
///
/// Trotter2ImplCA((2, op), deltaT, target);
/// ```
operation Trotter2ImplCA<'T> ((nSteps : Int, op : ((Int, Double, 'T) => Unit : Adjoint, Controlled)), stepSize : Double, target : 'T) : Unit
{
body (...)
{
for (idx in 0 .. nSteps - 1)
{
op(idx, stepSize * 0.5, target);
}
for (idx in nSteps - 1 .. -1 .. 0)
{
op(idx, stepSize * 0.5, target);
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Recursive implementation of even-order Trotter–Suzuki integrator.
///
/// # Type Parameters
/// ## 'T
/// The type which each time step should act upon; typically, either
/// `Qubit[]` or `Qubit`.
///
/// # Input
/// ### Order
/// Order of Trotter-Suzuki integrator.
/// ### nSteps
/// The number of operations to be decomposed into time steps.
/// ### op
/// An operation which accepts an index input (type `Int`) and a time
/// input (type `Double`) and a quantum register (type `'T`) for decomposition.
/// ## stepSize
/// Multiplier on size of each step of the simulation.
/// ## target
/// A quantum register on which the operations act.
operation TrotterArbitraryImplCA<'T> (order:Int, (nSteps : Int, op : ((Int, Double, 'T) => Unit : Adjoint, Controlled)), stepSize : Double, target : 'T) : Unit
{
body (...)
{
if(order > 2){
let stepSizeOuter = _TrotterStepSize(order);
let stepSizeInner = 1.0 - 4.0 * stepSizeOuter;
TrotterArbitraryImplCA(order -2, (nSteps, op), stepSizeOuter * stepSize, target);
TrotterArbitraryImplCA(order -2, (nSteps, op), stepSizeOuter * stepSize, target);
TrotterArbitraryImplCA(order -2, (nSteps, op), stepSizeInner * stepSize, target);
TrotterArbitraryImplCA(order -2, (nSteps, op), stepSizeOuter * stepSize, target);
TrotterArbitraryImplCA(order -2, (nSteps, op), stepSizeOuter * stepSize, target);
}
elif(order == 2){
Trotter2ImplCA((nSteps, op), stepSize, target);
}
else{
Trotter1ImplCA((nSteps, op), stepSize, target);
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Computes Trotter step size in recursive implementaiton of
/// Trotter simulation algorithm.
function _TrotterStepSize (order: Int) : Double {
return 1.0 / (4.0 - PowD(4.0, 1.0 / (2.0 * ToDouble(order) - 1.0)));
}
/// # Summary
/// Returns an operation implementing the Trotter–Suzuki integrator for
/// a given operation.
///
/// # Type Parameters
/// ## 'T
/// The type which each time step should act upon; typically, either
/// `Qubit[]` or `Qubit`.
///
/// # Input
/// ### nSteps
/// The number of operations to be decomposed into time steps.
/// ### op
/// An operation which accepts an index input (type `Int`) and a time
/// input (type `Double`) for decomposition.
/// ## trotterOrder
/// Selects the order of the Trotter–Suzuki integrator to be used.
/// Order 1 and 2 are currently supported.
///
/// # Output
/// Returns a unitary implementing the Trotter–Suzuki integrator, where
/// the first parameter `Double` is the integration step size, and the
/// second parameter is the target acted upon.
///
/// # References
/// We use the implementation in
/// - [ *D. W. Berry, G. Ahokas, R. Cleve, B. C. Sanders* ](https://arxiv.org/abs/quant-ph/0508139)
function DecomposeIntoTimeStepsCA<'T> ((nSteps : Int, op : ((Int, Double, 'T) => Unit : Adjoint, Controlled)), trotterOrder : Int) : ((Double, 'T) => Unit : Adjoint, Controlled)
{
if (trotterOrder == 1)
{
return Trotter1ImplCA((nSteps, op), _, _);
}
elif (trotterOrder == 2)
{
return Trotter2ImplCA((nSteps, op), _, _);
}
elif(trotterOrder % 2 ==0){
return TrotterArbitraryImplCA(trotterOrder, (nSteps, op), _, _);
}
else
{
fail $"Odd order $order not yet supported.";
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Iterates a variable, say `arr`, through a Cartesian product
/// [ 0, bounds[0]-1 ] × [ 0, bounds[1]-1 ] × [ 0, bounds[Length(bounds)-1]-1 ]
/// and calls op(arr) for every element of the Cartesian product
operation IterateThroughCartesianProduct (bounds : Int[], op : (Int[] => Unit)) : Unit
{
mutable arr = new Int[Length(bounds)];
mutable finished = false;
repeat
{
if (not finished)
{
op(arr);
}
}
until (finished)
fixup
{
//computes the next element in the Cartesian product
set arr[0] = arr[0] + 1;
for (i in 0 .. Length(arr) - 2)
{
if (arr[i] == bounds[i])
{
set arr[i + 1] = arr[i + 1] + 1;
set arr[i] = 0;
}
}
if (arr[Length(arr) - 1] == bounds[Length(arr) - 1])
{
set finished = true;
}
}
}
/// # Summary
/// Iterates a variable, say arr, through Cartesian product
/// [ 0, bound - 1 ] × [ 0, bound - 1 ] × [ 0, bound - 1 ]
/// and calls op(arr) for every element of the Cartesian product
operation IterateThroughCartesianPower (power : Int, bound : Int, op : (Int[] => Unit)) : Unit
{
IterateThroughCartesianProduct(ConstantArray(power, bound), op);
}
}

Просмотреть файл

@ -1,14 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
// Library for classical arithmetic on complex numbers
/// # Summary
/// Polar representation of a complex number $c=r e^{i t}$.
///
@ -18,9 +20,10 @@ namespace Microsoft.Quantum.Canon
/// ## Second Parameter
/// `Double` is the phase $t \in \mathbb R$.
newtype ComplexPolar = (Double, Double);
/// # Summary
/// Returns the squared absolute value of a complex number type
/// Returns the squared absolute value of a complex number type
/// `Complex`.
///
/// # Input
@ -29,13 +32,15 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Squared absolute value $|c|^2 = x^2 + y^2$.
function AbsSquaredComplex(input : Complex) : Double {
let (real, imaginary) = input;
function AbsSquaredComplex (input : Complex) : Double
{
let (real, imaginary) = input!;
return real * real + imaginary * imaginary;
}
/// # Summary
/// Returns the absolute value of a complex number type
/// Returns the absolute value of a complex number type
/// `Complex`.
///
/// # Input
@ -44,12 +49,14 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Absolute value $|c| = \sqrt{x^2 + y^2}$.
function AbsComplex(input : Complex) : Double {
function AbsComplex (input : Complex) : Double
{
return Sqrt(AbsSquaredComplex(input));
}
/// # Summary
/// Returns the phase of a complex number type
/// Returns the phase of a complex number type
/// `Complex`.
///
/// # Input
@ -58,13 +65,15 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Phase $\text{Arg}[c] = \text{ArcTan}(y,x) \in (-\pi,\pi]$.
function ArgComplex(input : Complex) : Double {
let (real, imaginary) = input;
function ArgComplex (input : Complex) : Double
{
let (real, imaginary) = input!;
return ArcTan2(imaginary, real);
}
/// # Summary
/// Returns the squared absolute value of a complex number type
/// Returns the squared absolute value of a complex number type
/// `ComplexPolar`.
///
/// # Input
@ -73,13 +82,15 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Squared absolute value $|c|^2 = r^2$.
function AbsSquaredComplexPolar(input : ComplexPolar) : Double {
let (abs, arg) = input;
function AbsSquaredComplexPolar (input : ComplexPolar) : Double
{
let (abs, arg) = input!;
return abs * abs;
}
/// # Summary
/// Returns the absolute value of a complex number type
/// Returns the absolute value of a complex number type
/// `ComplexPolar`.
///
/// # Input
@ -88,13 +99,15 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Absolute value $|c| = r$.
function AbsComplexPolar(input : ComplexPolar) : Double {
let (abs, arg) = input;
function AbsComplexPolar (input : ComplexPolar) : Double
{
let (abs, arg) = input!;
return abs;
}
/// # Summary
/// Returns the phase of a complex number type
/// Returns the phase of a complex number type
/// `ComplexPolar`.
///
/// # Input
@ -103,11 +116,13 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Phase $\text{Arg}[c] = t$.
function ArgComplexPolar(input : ComplexPolar) : Double {
let (abs, arg) = input;
function ArgComplexPolar (input : ComplexPolar) : Double
{
let (abs, arg) = input!;
return arg;
}
/// # Summary
/// Converts a complex number of type `ComplexPolar` to a complex
/// number of type `Complex`.
@ -118,11 +133,13 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Complex number $c = x + i y$.
function ComplexPolarToComplex(input: ComplexPolar) : Complex {
let (abs, arg) = input;
function ComplexPolarToComplex (input : ComplexPolar) : Complex
{
let (abs, arg) = input!;
return Complex(abs * Cos(arg), abs * Sin(arg));
}
/// # Summary
/// Converts a complex number of type `Complex` to a complex
/// number of type `ComplexPolar`.
@ -133,8 +150,11 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// Complex number $c = r e^{i t}$.
function ComplexToComplexPolar(input: Complex) : ComplexPolar {
function ComplexToComplexPolar (input : Complex) : ComplexPolar
{
return ComplexPolar(AbsComplex(input), ArgComplex(input));
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Returns the constant $\ln(2)$, where $\ln$
/// is the natural (base-$e$) logarithm.
///
/// # Output
/// Returns a `Double` equal to $0.6931471805599453$.
function LogOf2 () : Double
{
return 0.6931471805599453;
}
}

Просмотреть файл

@ -1,11 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Represents an integer of the form p/q. Integer p is
/// the first element of the tuple and q is the second element
/// of the tuple.
newtype Fraction = (Int, Int);
/// # Summary
/// Computes the base-2 logarithm of a number.
///
@ -15,12 +25,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The base-2 logarithm $y = \log_2(x)$ such that $x = 2^y$.
function Lg(input: Double) : Double
function Lg (input : Double) : Double
{
// Fully-qualified name is required because Log also appears in Primitives
return Microsoft.Quantum.Extensions.Math.Log(input) / LogOf2();
return Log(input) / LogOf2();
}
/// # Summary
/// Given an array of integers, returns the largest element.
///
@ -30,19 +40,23 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The largest element of `values`.
function Max(values : Int[]) : Int
function Max (values : Int[]) : Int
{
mutable max = values[0];
let nTerms = Length(values);
for(idx in 0..nTerms - 1)
for (idx in 0 .. nTerms - 1)
{
if (values[idx] > max) {
if (values[idx] > max)
{
set max = values[idx];
}
}
return max;
}
/// # Summary
/// Given an array of integers, returns the smallest element.
///
@ -52,19 +66,23 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The smallest element of `values`.
function Min(value : Int[]) : Int
function Min (value : Int[]) : Int
{
mutable min = value[0];
let nTerms = Length(value);
for(idx in 0..nTerms - 1)
for (idx in 0 .. nTerms - 1)
{
if (value[idx] < min) {
if (value[idx] < min)
{
set min = value[idx];
}
}
return min;
}
/// # Summary
/// Computes the modulus between two real numbers.
///
@ -91,17 +109,19 @@ namespace Microsoft.Quantum.Canon {
/// // which is a multiple of 2.4.
/// let z = RealMod(3.6, 2.4, -1.2);
/// ```
function RealMod(value: Double, modulo: Double, minValue: Double) : Double {
let fractionalValue = 2.0 * PI() * ((value - minValue) / modulo - 0.5 );
function RealMod (value : Double, modulo : Double, minValue : Double) : Double
{
let fractionalValue = (2.0 * PI()) * ((value - minValue) / modulo - 0.5);
let cosFracValue = Cos(fractionalValue);
let sinFracValue = Sin(fractionalValue);
let moduloValue = 0.5 + ArcTan2(sinFracValue, cosFracValue) / ( 2.0 * PI() );
let moduloValue = 0.5 + ArcTan2(sinFracValue, cosFracValue) / (2.0 * PI());
let output = moduloValue * modulo + minValue;
return output;
}
// NB: .NET's Math library does not provide hyperbolic arcfunctions.
/// # Summary
/// Computes the inverse hyperbolic cosine of a number.
///
@ -111,12 +131,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A real number $y$ such that $x = \cosh(y)$.
function ArcCosh(x : Double) : Double
function ArcCosh (x : Double) : Double
{
// Fully-qualified name is required because Log also appears in Primitives
return Microsoft.Quantum.Extensions.Math.Log(x + Sqrt(x * x - 1.0));
return Log(x + Sqrt(x * x - 1.0));
}
/// # Summary
/// Computes the inverse hyperbolic secant of a number.
///
@ -126,12 +146,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A real number $y$ such that $x = \operatorname{sinh}(y)$.
function ArcSinh(x : Double) : Double
function ArcSinh (x : Double) : Double
{
// Fully-qualified name is required because Log also appears in Primitives
return Microsoft.Quantum.Extensions.Math.Log(x + Sqrt(x * x + 1.0));
return Log(x + Sqrt(x * x + 1.0));
}
/// # Summary
/// Computes the inverse hyperbolic tangent of a number.
///
@ -141,12 +161,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A real number $y$ such that $x = \tanh(y)$.
function ArcTanh(x : Double) : Double
function ArcTanh (x : Double) : Double
{
// Fully-qualified name is required because Log also appears in Primitives
return Microsoft.Quantum.Extensions.Math.Log((1.0 + x) / (1.0 - x)) * 0.5;
return Log((1.0 + x) / (1.0 - x)) * 0.5;
}
/// # Summary
/// Computes canonical residue of `value` modulo `modulus`.
/// # Input
@ -160,48 +180,74 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// This function behaves the way a mathematician would expect Mod function to behave,
/// as opposed to how operator `%` is behaving in C# and Q#.
function Modulus( value : Int , modulus : Int ) : Int
function Modulus (value : Int, modulus : Int) : Int
{
AssertBoolEqual( modulus > 0, true, "`modulus` must be positive" );
AssertBoolEqual(modulus > 0, true, $"`modulus` must be positive");
let r = value % modulus;
if( r < 0 ) {
if (r < 0)
{
return r + modulus;
} else {
}
else
{
return r;
}
}
/// # Summary
/// Let us denote expBase by x, power by p and modulus by N.
/// The function returns xᵖ mod N .
/// # Summary
/// Let us denote expBase by x, power by p and modulus by N.
/// The function returns xᵖ mod N .
/// We assume that N,x are positive and power is non-negative.
///
/// # Remarks
///
/// # Remarks
/// Takes time proportional to the number of bits in `power`, not the power itself
function ExpMod( expBase : Int, power : Int, modulus : Int ) : Int {
AssertBoolEqual( power >= 0, true, "`power` must be non-negative" );
AssertBoolEqual( modulus > 0, true, "`modulus` must be positive" );
AssertBoolEqual( expBase > 0, true, "`expBase` must be positive" );
function ExpMod (expBase : Int, power : Int, modulus : Int) : Int
{
AssertBoolEqual(power >= 0, true, $"`power` must be non-negative");
AssertBoolEqual(modulus > 0, true, $"`modulus` must be positive");
AssertBoolEqual(expBase > 0, true, $"`expBase` must be positive");
mutable res = 1;
mutable expPow2mod = expBase;
// express p as bit-string pₙ … p₀
let powerBitExpansion = BoolArrFromPositiveInt(power,BitSize(power));
// express p as bit-string pₙ … p₀
let powerBitExpansion = BoolArrFromPositiveInt(power, BitSize(power));
let expBaseMod = expBase % modulus;
for( k in 0 .. Length(powerBitExpansion) - 1 )
for (k in 0 .. Length(powerBitExpansion) - 1)
{
if( powerBitExpansion[k] ) {
if (powerBitExpansion[k])
{
// if bit pₖ is 1, multiply res by expBase^(2ᵏ) (mod `modulus`)
set res = (res * expPow2mod) % modulus;
}
// update value of expBase^(2ᵏ) (mod `modulus`)
set expPow2mod = expPow2mod * expPow2mod % modulus;
set expPow2mod = (expPow2mod * expPow2mod) % modulus;
}
return res;
}
/// # Summary
/// Internal recursive call to calculate the GCD.
function _gcd (signA : Int, signB : Int, r : (Int, Int), s : (Int, Int), t : (Int, Int)) : (Int, Int)
{
if (Snd(r) == 0)
{
return (Fst(s) * signA, Fst(t) * signB);
}
let quotient = Fst(r) / Snd(r);
let r_ = (Snd(r), Fst(r) - quotient * Snd(r));
let s_ = (Snd(s), Fst(s) - quotient * Snd(s));
let t_ = (Snd(t), Fst(t) - quotient * Snd(t));
return _gcd(signA, signB, r_, s_, t_);
}
/// # Summary
/// Computes tuple (u,v) such that u⋅a + v⋅b = GCD(a,b), where GCD is a
/// greatest common divisor of a and b. The GCD is always positive.
@ -217,29 +263,17 @@ namespace Microsoft.Quantum.Canon {
///
/// # References
/// - This implementation is according to https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
function ExtendedGCD( a : Int, b : Int ) : (Int, Int) {
function ExtendedGCD (a : Int, b : Int) : (Int, Int)
{
let signA = SignI(a);
let signB = SignI(b);
mutable s = (1, 0);
mutable t = (0, 1);
mutable r = (a*signA, b*signB);
repeat {}
until( Snd(r) == 0 )
fixup {
let quotient = Fst(r) / Snd(r);
set r = ( Snd(r), Fst(r) - quotient * Snd(r) );
set s = ( Snd(s), Fst(s) - quotient * Snd(s) );
set t = ( Snd(t), Fst(t) - quotient * Snd(t) );
}
return (Fst(s)*signA,Fst(t)*signB);
let s = (1, 0);
let t = (0, 1);
let r = (a * signA, b * signB);
return _gcd(signA, signB, r, s, t);
}
/// # Summary
/// Represents an integer of the form p/q. Integer p is
/// the first element of the tuple and q is the second element
/// of the tuple.
newtype Fraction = (Int,Int);
/// # Summary
/// Computes greatest common divisor of a and b. The GCD is always positive.
///
@ -251,49 +285,59 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// Greatest common divisor of a and b
function GCD( a : Int, b : Int ) : Int {
let (u,v) = ExtendedGCD(a,b);
return u*a + v*b;
function GCD (a : Int, b : Int) : Int
{
let (u, v) = ExtendedGCD(a, b);
return u * a + v * b;
}
/// # Summary
/// Finds a continued fraction convergent closest to `fraction`
/// with the denominator less or equal to `denominatorBound`
///
/// # Input
///
///
/// # Output
/// Continued fraction closest to `fraction`
/// with the denominator less or equal to `denominatorBound`
function ContinuedFractionConvergent ( fraction : Fraction, denominatorBound : Int )
: Fraction {
AssertBoolEqual(denominatorBound > 0, true, "Denominator bound must be positive" );
let (a,b) = fraction;
/// # Summary
/// Internal recursive call to calculate the GCD with a bound
function _gcd_continued (signA : Int, signB : Int, r : (Int, Int), s : (Int, Int), t : (Int, Int), denominatorBound : Int) : Fraction
{
if (Snd(r) == 0 || AbsI(Snd(s)) > denominatorBound)
{
if (Snd(r) == 0 && AbsI(Snd(s)) <= denominatorBound)
{
return Fraction(-Snd(t) * signB, Snd(s) * signA);
}
return Fraction(-Fst(t) * signB, Fst(s) * signA);
}
let quotient = Fst(r) / Snd(r);
let r_ = (Snd(r), Fst(r) - quotient * Snd(r));
let s_ = (Snd(s), Fst(s) - quotient * Snd(s));
let t_ = (Snd(t), Fst(t) - quotient * Snd(t));
return _gcd_continued(signA, signB, r_, s_, t_, denominatorBound);
}
/// # Summary
/// Finds a continued fraction convergent closest to `fraction`
/// with the denominator less or equal to `denominatorBound`
///
/// # Input
///
///
/// # Output
/// Continued fraction closest to `fraction`
/// with the denominator less or equal to `denominatorBound`
function ContinuedFractionConvergent (fraction : Fraction, denominatorBound : Int) : Fraction
{
AssertBoolEqual(denominatorBound > 0, true, $"Denominator bound must be positive");
let (a, b) = fraction!;
let signA = SignI(a);
let signB = SignI(b);
mutable s = (1, 0);
mutable t = (0, 1);
mutable r = (a*signA, b*signB);
repeat {}
until( Snd(r) == 0 || AbsI(Snd(s)) > denominatorBound )
fixup {
let quotient = Fst(r) / Snd(r);
set r = ( Snd(r), Fst(r) - quotient * Snd(r) );
set s = ( Snd(s), Fst(s) - quotient * Snd(s) );
set t = ( Snd(t), Fst(t) - quotient * Snd(t) );
}
if( Snd(r) == 0 && AbsI(Snd(s)) <= denominatorBound ) {
return Fraction(-Snd(t)*signB, Snd(s)*signA);
}
return Fraction(-Fst(t)*signB, Fst(s)*signA);
let s = (1, 0);
let t = (0, 1);
let r = (a * signA, b * signB);
return _gcd_continued(signA, signB, r, s, t, denominatorBound);
}
/// # Summary
/// # Summary
/// Returns true if a and b are co-prime and false otherwise.
///
/// # Input
@ -305,11 +349,13 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// True, if a and b are co-prime (e.g. their greatest common divisor is 1 ),
/// and false otherwise
function IsCoprime( a : Int, b : Int ) : Bool {
let (u,v) = ExtendedGCD(a,b);
return u*a + v*b == 1;
function IsCoprime (a : Int, b : Int) : Bool
{
let (u, v) = ExtendedGCD(a, b);
return u * a + v * b == 1;
}
/// # Summary
/// Returns b such that `a`⋅b = 1 (mod `modulus`)
///
@ -321,15 +367,28 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// Integer b such that a⋅`b` = 1 (mod `modulus`)
function InverseMod( a : Int, modulus : Int ) : Int {
let (u,v) = ExtendedGCD(a,modulus);
let gcd = u*a + v*modulus;
AssertBoolEqual(
gcd == 1,
true, "`a` and `modulus` must be co-prime" );
return Modulus(u,modulus);
function InverseMod (a : Int, modulus : Int) : Int
{
let (u, v) = ExtendedGCD(a, modulus);
let gcd = u * a + v * modulus;
AssertBoolEqual(gcd == 1, true, $"`a` and `modulus` must be co-prime");
return Modulus(u, modulus);
}
/// # Summary
/// Helper function used to recursively calculate the bitsize of a value.
function _bitsize (val : Int, bitsize : Int) : Int
{
if (val == 0)
{
return bitsize;
}
return _bitsize(val / 2, bitsize + 1);
}
/// # Summary
/// For a non-negative integer `a`, returns the smallest $n$ such
/// that $a < 2^n$.
@ -340,21 +399,15 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The bit-size of `a`.
function BitSize( a : Int ) : Int {
AssertBoolEqual(a >= 0 , true, "`a` must be non-negative");
mutable bitsize = 0;
mutable val = a;
repeat{}
until( val == 0 )
fixup {
set bitsize = bitsize + 1;
set val = val / 2;
}
return bitsize;
function BitSize (a : Int) : Int
{
AssertBoolEqual(a >= 0, true, $"`a` must be non-negative");
return _bitsize(a, 0);
}
/// # Summary
/// Given an array $x$ of type `Double[]`, this returns the $p$-norm
/// Given an array $x$ of type `Double[]`, this returns the $p$-norm
/// $\|x\|_p= (\sum_{j}|x_j|^{p})^{1/p}$.
///
/// # Input
@ -363,18 +416,25 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The $p$-norm $\|x\|_p$.
function PNorm(p: Double, array: Double[]) : Double {
if(p < 1.0){
fail "PNorm failed. `p` must be >= 1.0";
function PNorm (p : Double, array : Double[]) : Double
{
if (p < 1.0)
{
fail $"PNorm failed. `p` must be >= 1.0";
}
let nElements = Length(array);
mutable norm = 0.0;
for(idx in 0..nElements-1){
set norm = norm + PowD(AbsD(array[idx]),p);
for (idx in 0 .. nElements - 1)
{
set norm = norm + PowD(AbsD(array[idx]), p);
}
return PowD(norm,1.0/p);
return PowD(norm, 1.0 / p);
}
/// # Summary
/// Given an array $x$ of type `Double[]`, this returns an array where
/// all elements are divided by the $p$-norm $\|x\|_p$.
@ -388,19 +448,28 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.PNorm
function PNormalize(p: Double, array: Double[]) : Double[] {
function PNormalize (p : Double, array : Double[]) : Double[]
{
let nElements = Length(array);
let norm = PNorm(p, array);
if(norm == 0.0){
if (norm == 0.0)
{
return array;
}
else{
else
{
mutable output = new Double[nElements];
for(idx in 0..nElements-1){
for (idx in 0 .. nElements - 1)
{
set output[idx] = array[idx] / norm;
}
return output;
}
}
}

118
Canon/src/Math/Random.qs Normal file
Просмотреть файл

@ -0,0 +1,118 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
// DESIGN NOTES:
// Q# functions *CANNOT* have side effects. Since random sampling is a side
// effect, this immediately implies that any random number generation is modeled
// as an operation. That in turn implies that random number generation calls inside
// another operation will break adjointability and controllability.
/// # Summary
/// Generates a random number uniformly sampled in the interval
/// $[0, 2^{\texttt{maxBits}} - 1]$.
///
/// # Input
/// ## maxBits
/// The number of classical bits required to represent the largest integer
/// that could be returned by this operation.
///
/// # Output
/// An integer $x$ uniformly at random from the given interval;
/// that is, with $\Pr(x) = \frac{1}{2^{\texttt{maxBits}}}$.
///
/// # Remarks
/// This function calls <xref:microsoft.quantum.primitive.random>, so
/// its randomess depends on the implementation of `Random`.
operation RandomIntPow2 (maxBits : Int) : Int
{
mutable number = 0;
for (idxBit in 0 .. maxBits - 1)
{
let bit = Random([0.5, 0.5]);
set number = number + bit * 2 ^ idxBit;
}
return number;
}
/// # Summary
/// Generates a random number uniformly sampled in the interval
/// $[0, \texttt{maxInt})$.
///
/// # Input
/// ## maxInt
/// An integer one larger than the largest integer to be
/// returned by this operation.
///
/// # Output
/// An integer $x$ uniformly at random from the given interval;
/// that is, with $\Pr(x) = \frac{1}{\texttt{maxInt}}$.
///
/// # Remarks
/// This operation uses postselection of an integer drawn from
/// a uniform distribution whose maximum is a power of two,
/// and thus may not make a constant number of calls to the
/// underlying source of random classical bits.
///
/// # Remarks
/// This function calls <xref:microsoft.quantum.primitive.random>, so
/// its randomess depends on the implementation of `Random`.
operation RandomInt (maxInt : Int) : Int
{
mutable nBits = 0;
mutable output = 0;
set nBits = Ceiling(Lg(ToDouble(maxInt)));
repeat
{
set output = RandomIntPow2(nBits);
}
until (output < maxInt)
fixup
{
}
return output;
}
/// # Summary
/// Returns a random real number in the interval $[0, 1)$.
///
/// # Input
/// ## bitsRandom
/// The number of bits of precision with which the random number
/// should be sampled.
///
/// # Output
/// A real number $x = k / 2^{\texttt{bitsRandom} - 1}$ for an integer
/// $k$ sampled from the interval $[0, 2^{\texttt{bitsRandom}})$
/// with probability $\Pr(k) = 1 / 2^{\texttt{bitsRandom}}$.
///
/// # Remarks
/// This function calls <xref:microsoft.quantum.primitive.random>, so
/// its randomess depends on the implementation of `Random`.
operation RandomReal (bitsRandom : Int) : Double
{
if (bitsRandom < 1)
{
fail $"Number of random bits must be greater than 0.";
}
return ToDouble(RandomIntPow2(bitsRandom)) / ToDouble(2 ^ (bitsRandom - 1));
}
}

259
Canon/src/Multiplexer.qs Normal file
Просмотреть файл

@ -0,0 +1,259 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Applies multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () : Adjoint, Controlled))`
/// is a fuction that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// ## index
/// $n$-qubit control register that encodes number states $\ket{j}$ in
/// big-endian format.
///
/// ## target
/// Generic qubit register that $V_j$ acts on.
///
/// # Remarks
/// `coefficients` will be padded with identity elements if
/// fewer than $2^n$ are specified. This implementation uses
/// $n-1$ auxillary qubits.
///
/// # References
/// - [ *Andrew M. Childs, Dmitri Maslov, Yunseong Nam, Neil J. Ross, Yuan Su*,
/// arXiv:1711.10980](https://arxiv.org/abs/1711.10980)
operation MultiplexOperationsFromGenerator<'T>(unitaryGenerator : (Int, (Int -> ('T => Unit : Adjoint, Controlled))), index: BigEndian, target: 'T) : Unit {
body (...) {
let (nUnitaries, unitaryFunction) = unitaryGenerator;
let unitaryGeneratorWithOffset = (nUnitaries, 0, unitaryFunction);
if (Length(index!) == 0) {
fail "MultiplexOperations failed. Number of index qubits must be greater than 0.";
}
if (nUnitaries > 0) {
let auxillary = new Qubit[0];
Adjoint MultiplexOperationsFromGenerator_(unitaryGeneratorWithOffset, auxillary, index, target);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// Implementation step of `MultiplexOperationsFromGenerator`.
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperationsFromGenerator
operation MultiplexOperationsFromGenerator_<'T>(unitaryGenerator : (Int, Int, (Int -> ('T => Unit : Adjoint, Controlled))), auxillary: Qubit[], index: BigEndian, target: 'T) : Unit {
body (...) {
let nIndex = Length(index!);
let nStates = 2^nIndex;
let (nUnitaries, unitaryOffset, unitaryFunction) = unitaryGenerator;
let nUnitariesLeft = MinI(nUnitaries, nStates/2);
let nUnitariesRight = MinI(nUnitaries, nStates);
let leftUnitaries = (nUnitariesLeft, unitaryOffset, unitaryFunction);
let rightUnitaries = (nUnitariesRight-nUnitariesLeft, unitaryOffset + nUnitariesLeft, unitaryFunction);
let newControls = BigEndian(index![1..nIndex-1]);
if(nUnitaries > 0){
if(Length(auxillary) == 1 && nIndex==0){
// Termination case
(Controlled Adjoint (unitaryFunction(unitaryOffset)))(auxillary, target);
}
elif(Length(auxillary) == 0 && nIndex>=1){
// Start case
let newauxillary = [index![0]];
if(nUnitariesRight > 0){
MultiplexOperationsFromGenerator_(rightUnitaries, newauxillary, newControls, target);
}
X(newauxillary[0]);
MultiplexOperationsFromGenerator_(leftUnitaries, newauxillary, newControls, target);
X(newauxillary[0]);
}
else{
// Recursion that reduces nIndex by 1 & sets Length(auxillary) to 1.
using(newauxillary = Qubit[1]){
let op = LogicalANDMeasAndFix_(_, _);
// Naive measurement-free approach uses 4x more T gates with
// let op = (Controlled X);
op(auxillary + [index![0]], newauxillary[0]);
if(nUnitariesRight > 0){
MultiplexOperationsFromGenerator_(rightUnitaries, newauxillary, newControls, target);
}
(Controlled X)(auxillary, newauxillary[0]);
MultiplexOperationsFromGenerator_(leftUnitaries, newauxillary, newControls, target);
(Controlled X)(auxillary, newauxillary[0]);
(Adjoint op)(auxillary + [index![0]], newauxillary[0]);
}
}
}
}
adjoint auto;
controlled (controlRegister, (...)) {
MultiplexOperationsFromGenerator_(unitaryGenerator, auxillary + controlRegister, index, target);
}
adjoint controlled auto;
}
/// # Summary
/// Applies multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () : Adjoint, Controlled))`
/// is a fuction that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// ## index
/// $n$-qubit control register that encodes number states $\ket{j}$ in
/// big-endian format.
///
/// ## target
/// Generic qubit register that $V_j$ acts on.
///
/// # Remarks
/// `coefficients` will be padded with identity elements if
/// fewer than $2^n$ are specified. This version is implemented
/// directly by looping through n-controlled unitary operators.
operation MultiplexOperationsBruteForceFromGenerator<'T>(unitaryGenerator : (Int, (Int -> ('T => Unit : Adjoint, Controlled))), index: BigEndian, target: 'T) : Unit {
body (...) {
let nIndex = Length(index!);
let nStates = 2^nIndex;
let (nUnitaries, unitaryFunction) = unitaryGenerator;
for(idxOp in 0..MinI(nStates,nUnitaries)-1){
(ControlledOnInt(idxOp, unitaryFunction(idxOp)))(Reverse(index!),target);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// Returns a multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () : Adjoint, Controlled))`
/// is a fuction that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// # Output
/// A multiply-controlled unitary operation $U$ that applies unitaries
/// described by `unitaryGenerator`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperationsFromGenerator
function MultiplexerFromGenerator(unitaryGenerator : (Int, (Int -> (Qubit[] => Unit : Adjoint, Controlled)))) : ((BigEndian, Qubit[]) => Unit : Adjoint, Controlled) {
return MultiplexOperationsFromGenerator(unitaryGenerator, _, _);
}
/// # Summary
/// Returns a multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () : Adjoint, Controlled))`
/// is a fuction that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// # Output
/// A multiply-controlled unitary operation $U$ that applies unitaries
/// described by `unitaryGenerator`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexerBruteForceFromGenerator
function MultiplexerBruteForceFromGenerator(unitaryGenerator : (Int, (Int -> (Qubit[] => Unit : Adjoint, Controlled)))) : ((BigEndian, Qubit[]) => Unit : Adjoint, Controlled) {
return MultiplexOperationsBruteForceFromGenerator(unitaryGenerator, _, _);
}
/// # Summary
/// Computes the logical AND of multiple qubits.
/// # Input
/// ## ctrlRegister
/// Qubits input to the multiple-input AND gate.
/// ## target
/// Qubit on which output of AND is written to. This is
/// assumed to always start in the $\ket{0}$ state.
/// # Remarks
/// When `ctrlRegister` has exactly $2$ qubits,
/// this is equivalent to the `CCNOT` operation but phase with a phase
/// $e^{i\Pi/2}$ on $\ket{001}$ and $-e^{i\Pi/2}$ on $\ket{101}$ and $\ket{011}$.
/// The Adjoint is also measure-and-fixup approach that is the inverse
/// of the original operation only in special cases (see references),
/// but uses fewer T-gates.
///
/// # References
/// - [ *Craig Gidney*, 1709.06648](https://arxiv.org/abs/1709.06648)
operation LogicalANDMeasAndFix_ (ctrlRegister: Qubit[], target: Qubit) : Unit
{
body (...)
{
if(Length(ctrlRegister) == 2){
let c1 = ctrlRegister[0];
let c2 = ctrlRegister[1];
H(target);
T(target);
CNOT(c1,target);
CNOT(c2,target);
CNOT(target,c1);
CNOT(target,c2);
(Adjoint T)(c1);
(Adjoint T)(c2);
T(target);
CNOT(target,c2);
CNOT(target,c1);
H(target);
S(target);
}
else{
(Controlled X)(ctrlRegister, target);
}
}
adjoint (...) {
if(Length(ctrlRegister) == 2){
let c1 = ctrlRegister[0];
let c2 = ctrlRegister[1];
H(target);
let Meas = M(target);
if (Meas == One) {
H(c2);
CNOT(c1,c2);
H(c2);
X(target);
}
}
else{
(Controlled X)(ctrlRegister, target);
}
}
}
}

51
Canon/src/NoOp.qs Normal file
Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
/// # Summary
/// Performs the identity operation (no-op) on an argument.
///
/// # Description
/// This operation takes a value of any type and does nothing to it.
/// This can be useful whenever an input of an operation type is expected,
/// but no action should be taken.
/// For instance, if a particular error correction syndrome indicates that
/// no error has occured, `NoOp<Qubit[]>` may be the correct recovery
/// procedure.
/// Similarly, if an operation expects a state preparation procedure as
/// input, `NoOp<Qubit[]>` can be used to prepare the state
/// $\ket{0 \cdots 0}$.
///
/// # Input
/// ## input
/// A value to be ignored.
///
/// # Remarks
/// In almost all cases, the type parameter for `NoOp` needs to be specified
/// explicitly. For instance, `NoOp<Qubit>` is identical to
/// @"Microsoft.Quantum.Primitive.I".
///
/// # See Also
/// - Microsoft.Quantum.Primitive.I
operation NoOp<'T>(input : 'T) : Unit {
body (...) {}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Ignores the output of an operation or function.
///
/// # Input
/// ## value
/// A value to be ignored.
function Ignore<'T> (value : 'T) : Unit
{
return ();
}
}

62
Canon/src/Parity.qs Normal file
Просмотреть файл

@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
/// # Summary
/// This computes the parity of qubits $\ket{q_0} \ket{q_1} \cdots$
/// in-place, following the pattern
/// $\ket{q_0} \ket{q_0 \oplus q_1} \ket{q_0 \oplus q_1 \oplus q_2} \cdots$.
///
/// # Input
/// ## qubits
/// Array of qubits on which parity is computed
/// and stored.
operation CNOTChain(qubits: Qubit[]) : Unit {
body (...) {
for (idxQubit in 0..Length(qubits) - 2){
CNOT(qubits[idxQubit], qubits[idxQubit + 1]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This computes the parity of qubits initially in the state
/// $\ket{q_0} \ket{q_1} \cdots \ket{q_{\text{target}}}$ in-place,
/// such that the final state is given by
/// $\ket{q_0} \ket{q_1 \oplus q_0} \cdots \ket{q_{n - 1} \oplus \cdots \oplus q_0 \oplus q_{\text{target}}}$.
///
/// # Input
/// ## qubits
/// Array of qubits on which the parity is computed.
/// ## targetQubit
/// Final qubit into which the parity of 'qubits' is XORed.
///
/// # Remarks
/// The following are equivalent:
/// ```Q#
/// CNOTChainTarget(Most(qs), Last(qs));
/// CNOTChain(qs);
/// ```
operation CNOTChainTarget(qubits: Qubit[], targetQubit: Qubit) : Unit {
body (...) {
let allQubits = qubits + [targetQubit];
CNOTChain(allQubits);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This computes the exclusive-OR of two bits.
function XOR(bit1: Bool, bit2: Bool) : Bool {
return (bit1 || bit2) && (not bit1 || not bit2);
}
}

Просмотреть файл

@ -1,32 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
// Design notes:
// The APIs for the iterative and quantum phase estimation algorithms are
// parameterized in terms of discrete-time oracles as defined in the OracleTypes.qs
// source file. Constructing such oracle definitions can be done with operations
// acting on other operations, making heavy use of partial application internally.
//
// E.g.:
// let DiscreteOracle = OracleToDiscrete(U);
// DiscretePhaseEstimationIteration(oracle, pow, theta, targetState, control);
// let datum = M(control);
//
// This design then enables providing more efficient implementations of U^m
// to be provided by the user for specific U, while providing a sensible
// "default" for operations which cannot be fast-forwarded by taking advantage
// of their definitions.
//
// Finally, we also ensure that quantum arguments are placed last to follow
// standard conventions for partial application. In particular, this allows for
// the discrete and continuous phase estimation iterations to be used in
// an allocate-op-measure pattern; we may soon want to abstract that away.
/// # Summary
/// Performs a single iteration of an iterative (classically-controlled) phase
/// estimation algorithm using integer powers of a unitary oracle.
@ -44,31 +47,32 @@ namespace Microsoft.Quantum.Canon {
/// acting on the target state.
/// ## targetState
/// Register of state acted upon by the given unitary oracle.
operation DiscretePhaseEstimationIteration( oracle : DiscreteOracle, power : Int, theta : Double, targetState : Qubit[], controlQubit : Qubit) : ()
operation DiscretePhaseEstimationIteration (oracle : DiscreteOracle, power : Int, theta : Double, targetState : Qubit[], controlQubit : Qubit) : Unit
{
// NB: We accept the control qubit as input so that we can allow for this operation
// to subject to the adjoint and control modifiers (that is, such that we do not need
// a return statement, but rather *act* on the given qubits).
body {
body (...)
{
// Find the actual inversion angle by rescaling with the power of the
// oracle.
let inversionAngle = -theta * ToDouble(power);
// Prepare the control qubit.
H(controlQubit);
Rz(inversionAngle, controlQubit);
(Controlled oracle)([controlQubit], (power, targetState));
Controlled oracle!([controlQubit], (power, targetState));
// Return the control qubit to the appropriate measurement basis.
H(controlQubit);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Performs a single iteration of an iterative (classically-controlled) phase
/// estimation algorithm using arbitrary real powers of a unitary oracle.
@ -86,36 +90,40 @@ namespace Microsoft.Quantum.Canon {
/// acting on the target state.
/// ## targetState
/// Register of state acted upon by the given unitary oracle.
operation ContinuousPhaseEstimationIteration( oracle : ContinuousOracle, time : Double, theta : Double, targetState : Qubit[], controlQubit : Qubit) : ()
operation ContinuousPhaseEstimationIteration (oracle : ContinuousOracle, time : Double, theta : Double, targetState : Qubit[], controlQubit : Qubit) : Unit
{
body {
body (...)
{
let inversionAngle = -(theta * time);
// Prepare the control qubit.
H(controlQubit);
Rz(inversionAngle, controlQubit);
(Controlled oracle)([controlQubit], (time, targetState));
Controlled oracle!([controlQubit], (time, targetState));
// Return the control qubit to the appropriate measurement basis.
H(controlQubit);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation PrepAndMeasurePhaseEstImpl(wInv : Double, t : Double, op : ((Double, Double, Qubit) => ())) : Result {
body {
mutable datum = Zero;
using (register = Qubit[1]) {
op(t, wInv, register[0]);
set datum = MResetZ(register[0]);
}
return datum;
operation PrepAndMeasurePhaseEstImpl (wInv : Double, t : Double, op : ((Double, Double, Qubit) => Unit)) : Result
{
mutable datum = Zero;
using (register = Qubit[1])
{
op(t, wInv, register[0]);
set datum = MResetZ(register[0]);
}
return datum;
}
}

Просмотреть файл

@ -1,12 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Testing;
/// # Summary
/// Performs the quantum phase estimation algorithm for a given oracle U and targetState,
/// reading the phase into a big-endian quantum register.
@ -22,28 +24,29 @@ namespace Microsoft.Quantum.Canon
/// to control the provided oracle, and that will contain the a representation of $\phi$ following
/// the application of this operation. The controlRegister is assumed to start in the initial
/// state $\ket{00\cdots 0}$, where the length of the register indicates the desired precision.
operation QuantumPhaseEstimation(
oracle : DiscreteOracle,
targetState : Qubit[],
controlRegister : BigEndian) : ()
operation QuantumPhaseEstimation (oracle : DiscreteOracle, targetState : Qubit[], controlRegister : BigEndian) : Unit
{
body {
let nQubits = Length(controlRegister);
AssertAllZeroTol(controlRegister, 1e-10);
ApplyToEachCA(H, controlRegister);
for (idxControlQubit in 0..(nQubits - 1)) {
let control = controlRegister[idxControlQubit];
let power = 2 ^ (nQubits - idxControlQubit - 1);
(Controlled oracle)([control], (power, targetState));
body (...)
{
let nQubits = Length(controlRegister!);
AssertAllZeroTol(controlRegister!, 1E-10);
ApplyToEachCA(H, controlRegister!);
for (idxControlQubit in 0 .. nQubits - 1)
{
let control = (controlRegister!)[idxControlQubit];
let power = 2 ^ ((nQubits - idxControlQubit) - 1);
Controlled oracle!([control], (power, targetState));
}
(Adjoint QFT)(controlRegister);
Adjoint QFT(controlRegister);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Performs the robust non-terative quantum phase estimation algorithm for a given oracle $U$ and eigenstate,
/// and provides a single real-valued estimate of the phase with variance scaling at the Heisenberg limit.
///
/// # Input
/// ## oracle
/// An operation implementing $U^m$ for given integer powers $m$.
/// ## targetState
/// A quantum register that $U$ acts on. If it stores an eigenstate
/// $\ket{\phi}$ of $U$, then $U\ket{\phi} = e^{i\phi} \ket{\phi}$
/// for $\phi\in(-\pi,\pi]$ an unknown phase.
/// ## bitsPrecision
/// This provides an estimate of $\phi$ with standard deviation
/// $\sigma \le 2\pi / 2^\text{bitsPrecision}$ using a number of queries scaling like $\sigma \le 10.7 \pi / \text{# of queries}$.
///
/// # Remarks
/// In the limit of a large number of queries, Cramer-Rao lower bounds
/// for the standard deviation of the estimate of $\phi$ satisfy
/// $\sigma \ge 2 \pi / \text{# of queries}$.
///
/// # References
/// - Robust Calibration of a Universal Single-Qubit Gate-Set via Robust Phase Estimation
/// Shelby Kimmel, Guang Hao Low, Theodore J. Yoder
/// https://arxiv.org/abs/1502.02677
operation RobustPhaseEstimation (bitsPrecision : Int, oracle : DiscreteOracle, targetState : Qubit[]) : Double
{
let alpha = 2.5;
let beta = 0.5;
mutable thetaEst = ToDouble(0);
using (qubitAncilla = Qubit[1])
{
let q = qubitAncilla[0];
for (exponent in 0 .. bitsPrecision - 1)
{
let power = 2 ^ exponent;
mutable nRepeats = Ceiling(alpha * ToDouble(bitsPrecision - exponent) + beta);
if (nRepeats % 2 == 1)
{
// Ensures that nRepeats is even.
set nRepeats = nRepeats + 1;
}
mutable pZero = ToDouble(0);
mutable pPlus = ToDouble(0);
for (idxRep in 0 .. nRepeats - 1)
{
for (idxExperiment in 0 .. 1)
{
// Divide rotation by power to cancel the multiplication by power in DiscretePhaseEstimationIteration
let rotation = ((PI() * ToDouble(idxExperiment)) / 2.0) / ToDouble(power);
DiscretePhaseEstimationIteration(oracle, power, rotation, targetState, q);
let result = M(q);
if (result == Zero)
{
if (idxExperiment == 0)
{
set pZero = pZero + 1.0;
}
elif (idxExperiment == 1)
{
set pPlus = pPlus + 1.0;
}
}
Reset(q);
}
}
let deltaTheta = ArcTan2(pPlus - ToDouble(nRepeats) / 2.0, pZero - ToDouble(nRepeats) / 2.0);
let delta = RealMod(deltaTheta - thetaEst * ToDouble(power), 2.0 * PI(), -PI());
set thetaEst = thetaEst + delta / ToDouble(power);
}
Reset(q);
}
return thetaEst;
}
}

Просмотреть файл

@ -1,23 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Represents a discrete-time oracle $U^m$ for a fixed operation $U$
/// and a non-negative integer $m$.
newtype DiscreteOracle = ((Int, Qubit[]) => ():Adjoint,Controlled);
newtype DiscreteOracle = ((Int, Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// Represents a continuous-time oracle
/// $U(\delta t) : \ket{\psi(t)} \mapsto \ket{\psi(t + \delta t)}
/// for all times $t$, where $U$ is a fixed operation, and where
/// and $\delta t$ is a non-negative real number.
newtype ContinuousOracle = ((Double, Qubit[]) => ():Adjoint,Controlled);
newtype ContinuousOracle = ((Double, Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// Given an operation representing a "black-box" oracle, returns a discrete-time oracle
/// Given an operation representing a "black-box" oracle, returns a discrete-time oracle
/// which represents the "black-box" oracle repeated multiple times.
///
/// # Input
@ -25,16 +27,16 @@ namespace Microsoft.Quantum.Canon {
/// The operation to be exponentiated
///
/// # Output
/// An operation partially applied over the "black-box" oracle representing the discrete-time oracle
/// An operation partially applied over the "black-box" oracle representing the discrete-time oracle
///
/// # Example
/// `OracleToDiscrete(U)(3, target)` is equivalent to `U(target)` repeated three times.
operation OracleToDiscrete(blackBoxOracle : (Qubit[] => (): Adjoint, Controlled)) : DiscreteOracle
operation OracleToDiscrete (blackBoxOracle : (Qubit[] => Unit : Adjoint, Controlled)) : DiscreteOracle
{
body {
let oracle = DiscreteOracle(OperationPowImplCA(blackBoxOracle, _, _));
return oracle;
}
let oracle = DiscreteOracle(OperationPowImplCA(blackBoxOracle, _, _));
return oracle;
}
}

Просмотреть файл

@ -1,23 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Apply the Approximate Quantum Fourier Transform (AQFT) to a quantum register.
///
/// # Input
/// ## a
/// approximation parameter which determines at which level the controlled Z-rotations that
/// approximation parameter which determines at which level the controlled Z-rotations that
/// occur in the QFT circuit are pruned.
///
/// The approximation parameter a determines the pruning level of the Z-rotations, i.e.,
/// a ∈ {0..n} and all Z-rotations 2π/2ᵏ where k>a are
/// removed from the QFT circuit. It is known that for k >= log₂(n)+log₂(1/ε)+3
/// one can bound ||QFT-AQFT||<ε.
/// a ∈ {0..n} and all Z-rotations 2π/2ᵏ where k>a are
/// removed from the QFT circuit. It is known that for k >= log₂(n)+log₂(1/ε)+3
/// one can bound ||QFT-AQFT||<ε.
///
/// ## qs
/// quantum register of n qubits to which the Approximate Quantum Fourier Transform is applied.
///
@ -26,41 +29,45 @@ namespace Microsoft.Quantum.Canon {
///
/// The input and output are assumed to be encoded in big endian encoding.
///
///
/// # References
///
/// # References
/// - [ *M. Roetteler, Th. Beth*,
/// Appl. Algebra Eng. Commun. Comput.
/// 19(3): 177-193 (2008) ](http://doi.org/10.1007/s00200-008-0072-2)
/// - [ *D. Coppersmith* arXiv:quant-ph/0201067v1 ](https://arxiv.org/abs/quant-ph/0201067)
operation ApproximateQFT ( a: Int, qs: BigEndian) : () {
body {
operation ApproximateQFT (a : Int, qs : BigEndian) : Unit
{
body (...)
{
let nQubits = Length(qs!);
AssertBoolEqual(nQubits > 0, true, $"`Length(qs)` must be least 1");
AssertBoolEqual(a > 0 && a <= nQubits, true, $"`a` must be positive and less than `Length(qs)`");
let nQubits = Length(qs);
AssertBoolEqual( nQubits > 0, true, "`Length(qs)` must be least 1" );
AssertBoolEqual(
(a > 0) && ( a <= nQubits ), true,
"`a` must be positive and less than `Length(qs)`" );
for (i in 0 .. (nQubits - 1) ) {
for (j in 0..(i-1)) {
if ( (i-j) < a ) {
(Controlled R1Frac)( [qs[i]], (1, i - j, qs[j]) );
for (i in 0 .. nQubits - 1)
{
for (j in 0 .. i - 1)
{
if (i - j < a)
{
Controlled R1Frac([(qs!)[i]], (1, i - j, (qs!)[j]));
}
}
H(qs[i]);
H((qs!)[i]);
}
// Apply the bit reversal permutation to the quantum register as
// a side effect, such that we enforce the invariants specified
// by the BigEndian UDT.
SwapReverseRegister(qs);
SwapReverseRegister(qs!);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Performs the Quantum Fourier Transform on a quantum register containing an
/// integer in the big-endian representation.
@ -71,19 +78,23 @@ namespace Microsoft.Quantum.Canon {
///
/// # Remarks
/// The input and output are assumed to be in big endian encoding.
///
/// # See Also
///
/// # See Also
/// - @"microsoft.quantum.canon.approximateqft"
/// - @"microsoft.quantum.canon.qftle"
operation QFT ( qs : BigEndian ) : () {
body {
ApproximateQFT(Length(qs), qs);
operation QFT (qs : BigEndian) : Unit
{
body (...)
{
ApproximateQFT(Length(qs!), qs);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Performs the Quantum Fourier Transform on a quantum register containing an
/// integer in the little-endian representation.
@ -98,12 +109,18 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.qft"
operation QFTLE ( qs : LittleEndian ) : () {
body {
operation QFTLE (qs : LittleEndian) : Unit
{
body (...)
{
ApplyReversedOpBigEndianCA(QFT, qs);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,12 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Measures $Z \otimes Z \otimes \cdots \otimes Z$ on
/// a given register.
@ -17,18 +20,20 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The result of measuring $Z \otimes Z \otimes \cdots \otimes Z$.
operation MeasureAllZ(register : Qubit[]) : Result {
body {
let nQubits = Length(register);
mutable allZMeasurement = new Pauli[nQubits];
for (idxQubit in 0..nQubits - 1) {
set allZMeasurement[idxQubit] = PauliZ;
}
return Measure(allZMeasurement, register);
operation MeasureAllZ (register : Qubit[]) : Result
{
let nQubits = Length(register);
mutable allZMeasurement = new Pauli[nQubits];
for (idxQubit in 0 .. nQubits - 1)
{
set allZMeasurement[idxQubit] = PauliZ;
}
return Measure(allZMeasurement, register);
}
/// # Summary
/// Measures the identity operator $\boldone$ on a register
/// of qubits.
@ -51,12 +56,12 @@ namespace Microsoft.Quantum.Canon {
/// information about the trace preservation of a quantum process.
/// In particular, a target machine with lossy measurement should
/// replace this operation by an actual measurement of $\boldone$.
operation MeasureIdentity(register : Qubit[]) : Result {
body {
return Zero;
}
operation MeasureIdentity (register : Qubit[]) : Result
{
return Zero;
}
/// # Summary
/// Given a qubit, prepares that qubit in the maximally mixed
/// state $\boldone / 2$ by applying the depolarizing channel
@ -81,12 +86,12 @@ namespace Microsoft.Quantum.Canon {
/// to pure states, but it acts as described in expectation.
/// In particular, this operation can be used in process tomography
/// to measure the *non-unital* components of a channel.
operation PrepareSingleQubitIdentity(qubit : Qubit) : () {
body {
ApplyPauli([RandomSingleQubitPauli()], [qubit]);
}
operation PrepareSingleQubitIdentity (qubit : Qubit) : Unit
{
ApplyPauli([RandomSingleQubitPauli()], [qubit]);
}
/// # Summary
/// Given a register, prepares that register in the maximally mixed
/// state $\boldone / 2^N$ by applying the complete depolarizing
@ -99,12 +104,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - @"microsoft.quantum.canon.preparesinglequbitidentity"
operation PrepareIdentity(register : Qubit[]) : () {
body {
ApplyToEach(PrepareSingleQubitIdentity, register);
}
operation PrepareIdentity (register : Qubit[]) : Unit
{
ApplyToEach(PrepareSingleQubitIdentity, register);
}
/// # Summary
/// Given a preparation and measurement, estimates the frequency
/// with which that measurement succeeds (returns `Zero`) by
@ -132,30 +137,35 @@ namespace Microsoft.Quantum.Canon {
///
/// This is particularly important on target machines which respect
/// physical limitations, such that probabilities cannot be measured.
operation EstimateFrequency(preparation : (Qubit[] => ()), measurement : (Qubit[] => Result), nQubits : Int, nMeasurements : Int) : Double {
body {
mutable nUp = 0;
for (idxMeasurement in 0..nMeasurements - 1) {
using (register = Qubit[nQubits]) {
preparation(register);
let result = measurement(register);
if (result == Zero) {
// NB!!!!! This reverses Zero and One to use conventions
// common in the QCVV community. That is confusing
// but is confusing with an actual purpose.
set nUp = nUp + 1;
}
// NB: We absolutely must reset here, since preparation()
// and measurement() can each use randomness internally.
ApplyToEach(Reset, register);
operation EstimateFrequency (preparation : (Qubit[] => Unit), measurement : (Qubit[] => Result), nQubits : Int, nMeasurements : Int) : Double
{
mutable nUp = 0;
for (idxMeasurement in 0 .. nMeasurements - 1)
{
using (register = Qubit[nQubits])
{
preparation(register);
let result = measurement(register);
if (result == Zero)
{
// NB!!!!! This reverses Zero and One to use conventions
// common in the QCVV community. That is confusing
// but is confusing with an actual purpose.
set nUp = nUp + 1;
}
// NB: We absolutely must reset here, since preparation()
// and measurement() can each use randomness internally.
ApplyToEach(Reset, register);
}
return ToDouble(nUp) / ToDouble(nMeasurements);
}
return ToDouble(nUp) / ToDouble(nMeasurements);
}
/// # Summary
/// Given a single qubit initially in the $\ket{0}$ state, prepares the
/// qubit in the $+1$ eigenstate of a given Pauli operator, or in the
@ -168,20 +178,24 @@ namespace Microsoft.Quantum.Canon {
/// ## qubit
/// A qubit initially in the $\ket{0}$ state which is to be prepared in
/// the given basis.
operation PrepareQubit(basis : Pauli, qubit : Qubit) : () {
body {
if (basis == PauliI) {
PrepareSingleQubitIdentity(qubit);
} elif (basis == PauliX) {
H(qubit);
} elif (basis == PauliY) {
H(qubit);
S(qubit);
}
operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit
{
if (basis == PauliI)
{
PrepareSingleQubitIdentity(qubit);
}
elif (basis == PauliX)
{
H(qubit);
}
elif (basis == PauliY)
{
H(qubit);
S(qubit);
}
}
/// # Summary
/// Given two registers, prepares the maximally entangled state
/// $\bra{\beta_{00}}\ket{\beta_{00}}$ between each pair of qubits on the respective registers,
@ -192,23 +206,28 @@ namespace Microsoft.Quantum.Canon {
/// A qubit array in the $\ket{0\cdots 0}$ state
/// ## right
/// A qubit array in the $\ket{0\cdots 0}$ state
operation PrepareEntangledState(left : Qubit[], right : Qubit[]) : () {
body {
if (Length(left) != Length(right)) {
fail "Left and right registers must be the same length.";
operation PrepareEntangledState (left : Qubit[], right : Qubit[]) : Unit
{
body (...)
{
if (Length(left) != Length(right))
{
fail $"Left and right registers must be the same length.";
}
for (idxQubit in 0..Length(left) - 1) {
for (idxQubit in 0 .. Length(left) - 1)
{
H(left[idxQubit]);
(Controlled X)([left[idxQubit]], right[idxQubit]);
Controlled X([left[idxQubit]], right[idxQubit]);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Prepares the Choi–Jamiłkowski state for a given operation onto given reference
/// and target registers.
@ -244,58 +263,66 @@ namespace Microsoft.Quantum.Canon {
/// - @"microsoft.quantum.canon.preparechoistatec"
/// - @"microsoft.quantum.canon.preparechoistatea"
/// - @"microsoft.quantum.canon.preparechoistateca"
operation PrepareChoiState(op : (Qubit[] => ()), reference : Qubit[], target : Qubit[]) : () {
body {
PrepareEntangledState(reference, target);
op(target);
}
operation PrepareChoiState (op : (Qubit[] => Unit), reference : Qubit[], target : Qubit[]) : Unit
{
PrepareEntangledState(reference, target);
op(target);
}
/// # Summary
/// Prepares the Choi–Jamiłkowski state for a given operation with a controlled variant onto given reference
/// and target registers.
/// # See Also
/// - @"microsoft.quantum.canon.preparechoistate"
operation PrepareChoiStateC(op : (Qubit[] => () : Controlled), reference : Qubit[], target : Qubit[]) : () {
body {
operation PrepareChoiStateC (op : (Qubit[] => Unit : Controlled), reference : Qubit[], target : Qubit[]) : Unit
{
body (...)
{
PrepareEntangledState(reference, target);
op(target);
}
controlled auto
controlled distribute;
}
/// # Summary
/// Prepares the Choi–Jamiłkowski state for a given operation with an adjoint variant onto given reference
/// and target registers.
/// # See Also
/// - @"microsoft.quantum.canon.preparechoistate"
operation PrepareChoiStateA(op : (Qubit[] => () : Adjoint), reference : Qubit[], target : Qubit[]) : () {
body {
operation PrepareChoiStateA (op : (Qubit[] => Unit : Adjoint), reference : Qubit[], target : Qubit[]) : Unit
{
body (...)
{
PrepareEntangledState(reference, target);
op(target);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Prepares the Choi–Jamiłkowski state for a given operation with both controlled and adjoint variants onto given reference
/// and target registers.
/// and target registers.
///
/// # See Also
/// - @"microsoft.quantum.canon.preparechoistate"
operation PrepareChoiStateCA(op : (Qubit[] => () : Controlled, Adjoint), reference : Qubit[], target : Qubit[]) : () {
body {
operation PrepareChoiStateCA (op : (Qubit[] => Unit : Controlled, Adjoint), reference : Qubit[], target : Qubit[]) : Unit
{
body (...)
{
PrepareEntangledState(reference, target);
op(target);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Performs a single-qubit process tomography measurement in the Pauli
@ -334,27 +361,22 @@ namespace Microsoft.Quantum.Canon {
/// $$
/// where $M = 2 (\boldone + P)^\mathrm{T} / 2 \cdot (\boldone + Q) / 2$
/// is the effective measurement corresponding to $P$ and $Q$.
operation SingleQubitProcessTomographyMeasurement(
preparation : Pauli,
measurement : Pauli,
channel : (Qubit => ())
) : Result {
body {
mutable result = Zero;
using (register = Qubit[1]) {
let qubit = register[0];
PrepareQubit(preparation, qubit);
channel(qubit);
set result = Measure([measurement], [qubit]);
Reset(qubit);
}
return result;
operation SingleQubitProcessTomographyMeasurement (preparation : Pauli, measurement : Pauli, channel : (Qubit => Unit)) : Result
{
mutable result = Zero;
using (register = Qubit[1])
{
let qubit = register[0];
PrepareQubit(preparation, qubit);
channel(qubit);
set result = Measure([measurement], [qubit]);
Reset(qubit);
}
return result;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Private operation used to implement both the 5 qubit encoder and decoder.
///
@ -15,32 +18,35 @@ namespace Microsoft.Quantum.Canon {
/// an array holding 4 qubits which add redundancy.
///
/// # Remarks
/// The particular encoder chosen was taken from the paper V. Kliuchnikov and D. Maslov, "Optimization of Clifford Circuits,"
/// The particular encoder chosen was taken from the paper V. Kliuchnikov and D. Maslov, "Optimization of Clifford Circuits,"
/// Phys. Rev. Phys. Rev. A 88, 052307 (2013); https://arxiv.org/abs/1305.0810, Figure 4b) and requires a total of 11 gates.
operation FiveQubitCodeEncoderImpl(data : Qubit[], scratch : Qubit[]) : ()
operation FiveQubitCodeEncoderImpl (data : Qubit[], scratch : Qubit[]) : Unit
{
body {
(Controlled(X))(data, scratch[1]);
body (...)
{
Controlled X(data, scratch[1]);
H(data[0]);
H(scratch[0]);
(Controlled(X))(data, scratch[2]);
(Controlled(X))([scratch[0]], data[0]);
(Controlled(X))(data, scratch[1]);
(Controlled(X))([scratch[0]], scratch[3]);
Controlled X(data, scratch[2]);
Controlled X([scratch[0]], data[0]);
Controlled X(data, scratch[1]);
Controlled X([scratch[0]], scratch[3]);
H(scratch[0]);
H(data[0]);
(Controlled(X))([scratch[0]], scratch[2]);
(Controlled(X))(data, scratch[3]);
Controlled X([scratch[0]], scratch[2]);
Controlled X(data, scratch[3]);
// The last X below is to correct the signs of stabilizers.
// The 5-qubit code is non-CSS, so even if the circuit implements
// the correct symplectic matrix,
// it may differ from the desired one by a Pauli correction.
X(scratch[2]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Returns function that maps error syndrome measurements to the
/// appropriate error-correcting Pauli operators by table lookup for
@ -55,39 +61,41 @@ namespace Microsoft.Quantum.Canon {
/// By iterating over all errors of weight $1$, we obtain a total of $3\times 5=15$ possible non-trivial syndromes.
/// Together with the identity, a table of error and corresponding syndrom is built up. For the 5 qubit code
/// this table is given by: $X\_1: (0,0,0,1); X\_2: (1,0,0,0); X\_3: (1,1,0,0); X\_4: (0,1,1,0); X\_5: (0,0,1,1),
/// Z\_1: (1,0,1,0); Z\_2: (0,1,0,1); Z\_3: (0,0,1,0); Z\_4: (1,0,0,1); Z\_5: (0,1,0,0)$ with $Y_i$ obtained by adding the $X_i$ and $Z_i$ syndromes. Note that the
/// Z\_1: (1,0,1,0); Z\_2: (0,1,0,1); Z\_3: (0,0,1,0); Z\_4: (1,0,0,1); Z\_5: (0,1,0,0)$ with $Y_i$ obtained by adding the $X_i$ and $Z_i$ syndromes. Note that the
/// ordering in the table lookup recovery is given by converting the bitvectors to integers (using little endian).
///
/// # See Also
/// - Microsoft.Quantum.Canon.RecoveryFn
function FiveQubitCodeRecoveryFn() : RecoveryFn
function FiveQubitCodeRecoveryFn () : RecoveryFn
{
return TableLookupRecovery(
[ [PauliI; PauliI; PauliI; PauliI; PauliI];
[PauliI; PauliX; PauliI; PauliI; PauliI];
[PauliI; PauliI; PauliI; PauliI; PauliZ];
[PauliI; PauliI; PauliX; PauliI; PauliI];
[PauliI; PauliI; PauliZ; PauliI; PauliI];
[PauliZ; PauliI; PauliI; PauliI; PauliI];
[PauliI; PauliI; PauliI; PauliX; PauliI];
[PauliI; PauliI; PauliY; PauliI; PauliI];
[PauliX; PauliI; PauliI; PauliI; PauliI];
[PauliI; PauliI; PauliI; PauliZ; PauliI];
[PauliI; PauliZ; PauliI; PauliI; PauliI];
[PauliI; PauliY; PauliI; PauliI; PauliI];
[PauliI; PauliI; PauliI; PauliI; PauliX];
[PauliY; PauliI; PauliI; PauliI; PauliI];
[PauliI; PauliI; PauliI; PauliI; PauliY];
[PauliI; PauliI; PauliI; PauliY; PauliI] ]
);
[
[PauliI, PauliI, PauliI, PauliI, PauliI],
[PauliI, PauliX, PauliI, PauliI, PauliI],
[PauliI, PauliI, PauliI, PauliI, PauliZ],
[PauliI, PauliI, PauliX, PauliI, PauliI],
[PauliI, PauliI, PauliZ, PauliI, PauliI],
[PauliZ, PauliI, PauliI, PauliI, PauliI],
[PauliI, PauliI, PauliI, PauliX, PauliI],
[PauliI, PauliI, PauliY, PauliI, PauliI],
[PauliX, PauliI, PauliI, PauliI, PauliI],
[PauliI, PauliI, PauliI, PauliZ, PauliI],
[PauliI, PauliZ, PauliI, PauliI, PauliI],
[PauliI, PauliY, PauliI, PauliI, PauliI],
[PauliI, PauliI, PauliI, PauliI, PauliX],
[PauliY, PauliI, PauliI, PauliI, PauliI],
[PauliI, PauliI, PauliI, PauliI, PauliY],
[PauliI, PauliI, PauliI, PauliY, PauliI]
]);
}
/// # Summary
/// Encodes into the ⟦5, 1, 3⟧ quantum code.
/// Encodes into the ⟦5, 1, 3⟧ quantum code.
///
/// # Input
/// ## physRegister
/// A qubit representing an unencoded state. This array `Qubit[]` is of
/// A qubit representing an unencoded state. This array `Qubit[]` is of
/// length 1.
/// ## auxQubits
/// A register of auxiliary qubits that will be used to represent the
@ -95,73 +103,69 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// An array of physical qubits of type `LogicalRegister` that store the
/// encoded state.
/// encoded state.
///
/// # See Also
/// - Microsoft.Quantum.Canon.LogicalRegister
operation FiveQubitCodeEncoder(physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
operation FiveQubitCodeEncoder (physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
{
body {
FiveQubitCodeEncoderImpl(physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
FiveQubitCodeEncoderImpl(physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
/// # Summary
/// Decodes the ⟦5, 1, 3⟧ quantum code.
/// Decodes the ⟦5, 1, 3⟧ quantum code.
///
/// # Input
/// ## logicalRegister
/// An array of qubits representing the encoded 5-qubit code logical state.
///
/// # Output
/// A qubit array of length 1 representing the unencoded state in the
/// first parameter, together with auxiliary qubits in the second parameter.
/// A qubit array of length 1 representing the unencoded state in the
/// first parameter, together with auxillary qubits in the second parameter.
///
/// # See Also
/// - microsoft.quantum.canon.FiveQubitCodeEncoder
/// - Microsoft.Quantum.Canon.LogicalRegister
operation FiveQubitCodeDecoder( logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
operation FiveQubitCodeDecoder (logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
{
body {
let physRegister = [logicalRegister[0]];
let auxQubits = logicalRegister[1..4];
(Adjoint FiveQubitCodeEncoderImpl)(physRegister, auxQubits);
return (physRegister, auxQubits);
}
let physRegister = [(logicalRegister!)[0]];
let auxQubits = (logicalRegister!)[1 .. 4];
Adjoint FiveQubitCodeEncoderImpl(physRegister, auxQubits);
return (physRegister, auxQubits);
}
/// # Summary
/// Returns a QECC value representing the ⟦5, 1, 3⟧ code encoder and
/// decoder with in-place syndrome measurement.
///
/// # Output
/// Returns an implementation of a quantum error correction code by
/// Returns an implementation of a quantum error correction code by
/// specifying a `QECC` type.
///
/// # Remarks
/// This code was found independently in the following two papers:
/// - C. H. Bennett, D. DiVincenzo, J. A. Smolin and W. K. Wootters, "Mixed state entanglement and quantum error correction," Phys. Rev. A, 54 (1996) pp. 3824-3851; https://arxiv.org/abs/quant-ph/9604024 and
/// - R. Laflamme, C. Miquel, J. P. Paz and W. H. Zurek, "Perfect quantum error correction code," Phys. Rev. Lett. 77 (1996) pp. 198-201; https://arxiv.org/abs/quant-ph/9602019
operation FiveQubitCode() : QECC
operation FiveQubitCode () : QECC
{
body {
let e = EncodeOp(FiveQubitCodeEncoder);
let d = DecodeOp(FiveQubitCodeDecoder);
let s = SyndromeMeasOp(MeasureStabilizerGenerators(
[ [ PauliX; PauliZ; PauliZ; PauliX; PauliI ];
[ PauliI; PauliX; PauliZ; PauliZ; PauliX ];
[ PauliX; PauliI; PauliX; PauliZ; PauliZ ];
[ PauliZ; PauliX; PauliI; PauliX; PauliZ ] ],
_, MeasureWithScratch)
);
let code = QECC(e, d, s);
return code;
}
let e = EncodeOp(FiveQubitCodeEncoder);
let d = DecodeOp(FiveQubitCodeDecoder);
let g =
[
[PauliX, PauliZ, PauliZ, PauliX, PauliI],
[PauliI, PauliX, PauliZ, PauliZ, PauliX],
[PauliX, PauliI, PauliX, PauliZ, PauliZ],
[PauliZ, PauliX, PauliI, PauliX, PauliZ]
];
let s = SyndromeMeasOp(MeasureStabilizerGenerators(g, _, MeasureWithScratch));
let code = QECC(e, d, s);
return code;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Private operation used to implement both the Steane code encoder and decoder.
///
@ -13,25 +16,28 @@ namespace Microsoft.Quantum.Canon {
/// an array holding 1 qubit which is the input qubit.
/// ## scratch
/// an array holding 6 qubits which add redundancy.
operation SteaneCodeEncoderImpl(data : Qubit[], scratch : Qubit[]) : ()
operation SteaneCodeEncoderImpl (data : Qubit[], scratch : Qubit[]) : Unit
{
body {
H( scratch[0] );
H( scratch[2] );
H( scratch[5] );
CNOT( data[0], scratch[4] );
CNOT( scratch[5], scratch[1] );
CNOT( scratch[5], scratch[3] );
CNOT( scratch[1], data[0] );
CNOT( scratch[2], scratch[4] );
CNOT( scratch[0], scratch[4] );
CNOT( scratch[4], scratch[5] );
CNOT( scratch[2], scratch[3] );
CNOT( scratch[0], scratch[1] );
body (...)
{
H(scratch[0]);
H(scratch[2]);
H(scratch[5]);
CNOT(data[0], scratch[4]);
CNOT(scratch[5], scratch[1]);
CNOT(scratch[5], scratch[3]);
CNOT(scratch[1], data[0]);
CNOT(scratch[2], scratch[4]);
CNOT(scratch[0], scratch[4]);
CNOT(scratch[4], scratch[5]);
CNOT(scratch[2], scratch[3]);
CNOT(scratch[0], scratch[1]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Decoder for the X-part of the stabilizer group of the ⟦7, 1, 3⟧ Steane quantum code.
///
@ -46,7 +52,7 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// The chosen decoder uses the CSS code property of the ⟦7, 1, 3⟧ Steane code, i.e., it corrects X errors
/// and Z errors separately. A property of the code is that the location of the X, respectively, Z correction
/// to be applied is the 3-bit encoding of the X, respectively, Z syndrome when considered an integer.
/// to be applied is the 3-bit encoding of the X, respectively, Z syndrome when considered an integer.
///
/// # See Also
/// - Microsoft.Quantum.Canon.SteaneCodeRecoveryX
@ -55,30 +61,38 @@ namespace Microsoft.Quantum.Canon {
/// # References
/// - D. Gottesman, "Stabilizer Codes and Quantum Error Correction," Ph.D. Thesis, Caltech, 1997;
/// https://arxiv.org/abs/quant-ph/9705052
function SteaneCodeRecoveryX( syndrome : Syndrome ) : Pauli[]
function SteaneCodeRecoveryX (syndrome : Syndrome) : Pauli[]
{
let idxQubit = ResultAsInt(syndrome);
if (idxQubit == 0) {
let idxQubit = ResultAsInt(syndrome!);
if (idxQubit == 0)
{
return ConstantArray(7, PauliI);
}
return EmbedPauli(PauliZ, idxQubit - 1, 7);
}
/// # Summary
/// Decoder for the Z-part of the stabilizer group of the ⟦7, 1, 3⟧ Steane quantum code.
///
/// # See Also
/// - Microsoft.Quantum.Canon.SteaneCodeRecoveryX
/// - Microsoft.Quantum.Canon.SteaneCodeRecoveryFns
function SteaneCodeRecoveryZ( syndrome : Syndrome) : Pauli[]
function SteaneCodeRecoveryZ (syndrome : Syndrome) : Pauli[]
{
let idxQubit = ResultAsInt(syndrome);
if (idxQubit == 0) {
let idxQubit = ResultAsInt(syndrome!);
if (idxQubit == 0)
{
return ConstantArray(7, PauliI);
}
return EmbedPauli(PauliX, idxQubit - 1, 7);
}
/// # Summary
/// Decoder for combined X- and Z-parts of the stabilizer group of the
/// ⟦7, 1, 3⟧ Steane quantum code.
@ -91,10 +105,12 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.SteaneCodeRecoveryX
/// - Microsoft.Quantum.Canon.SteaneCodeRecoveryZ
function SteaneCodeRecoveryFns() : (RecoveryFn, RecoveryFn) {
function SteaneCodeRecoveryFns () : (RecoveryFn, RecoveryFn)
{
return (RecoveryFn(SteaneCodeRecoveryX), RecoveryFn(SteaneCodeRecoveryZ));
}
/// # Summary
/// An encoding operation that maps an unencoded quantum register to an encoded quantum register
/// under the ⟦7, 1, 3⟧ Steane quantum code.
@ -112,16 +128,14 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.LogicalRegister
/// - Microsoft.Quantum.Canon.SteaneCodeDecoder
operation SteaneCodeEncoder(physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
operation SteaneCodeEncoder (physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
{
body {
SteaneCodeEncoderImpl(physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
SteaneCodeEncoderImpl(physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
/// # Summary
/// An inverse encoding operation that maps an unencoded quantum register to an encoded quantum
/// register under the ⟦7, 1, 3⟧ Steane quantum code.
@ -147,18 +161,15 @@ namespace Microsoft.Quantum.Canon {
/// # References
/// - D. Gottesman, "Stabilizer Codes and Quantum Error Correction," Ph.D. Thesis, Caltech, 1997;
/// https://arxiv.org/abs/quant-ph/9705052
operation SteaneCodeDecoder( logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
operation SteaneCodeDecoder (logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
{
body {
let physRegister = [logicalRegister[0]];
let auxQubits = logicalRegister[1..6];
(Adjoint SteaneCodeEncoderImpl)(physRegister, auxQubits);
return (physRegister, auxQubits);
}
let physRegister = [(logicalRegister!)[0]];
let auxQubits = (logicalRegister!)[1 .. 6];
Adjoint SteaneCodeEncoderImpl(physRegister, auxQubits);
return (physRegister, auxQubits);
}
/// # Summary
/// Returns a CSS value representing the ⟦7, 1, 3⟧ Steane code encoder and
/// decoder with in-place syndrome measurement.
@ -170,27 +181,28 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// This code was found in the following paper:
/// - A. Steane, "Multiple Particle Interference and Quantum Error Correction", Proc. Roy. Soc. Lond. A452 (1996) pp. 2551; https://arxiv.org/abs/quant-ph/9601029.
operation SteaneCode() : CSS
operation SteaneCode () : CSS
{
body {
let e = EncodeOp(SteaneCodeEncoder);
let d = DecodeOp(SteaneCodeDecoder);
let sx = SyndromeMeasOp(MeasureStabilizerGenerators(
[ [ PauliX; PauliI; PauliX; PauliI; PauliX; PauliI; PauliX ];
[ PauliI; PauliX; PauliX; PauliI; PauliI; PauliX; PauliX ];
[ PauliI; PauliI; PauliI; PauliX; PauliX; PauliX; PauliX ] ],
_, MeasureWithScratch)
);
let sz = SyndromeMeasOp(MeasureStabilizerGenerators(
[ [ PauliZ; PauliI; PauliZ; PauliI; PauliZ; PauliI; PauliZ ];
[ PauliI; PauliZ; PauliZ; PauliI; PauliI; PauliZ; PauliZ ];
[ PauliI; PauliI; PauliI; PauliZ; PauliZ; PauliZ; PauliZ ] ],
_, MeasureWithScratch)
);
let code = CSS(e, d, sx, sz);
return code;
}
let e = EncodeOp(SteaneCodeEncoder);
let d = DecodeOp(SteaneCodeDecoder);
let xg =
[
[PauliX, PauliI, PauliX, PauliI, PauliX, PauliI, PauliX],
[PauliI, PauliX, PauliX, PauliI, PauliI, PauliX, PauliX],
[PauliI, PauliI, PauliI, PauliX, PauliX, PauliX, PauliX]
];
let zg =
[
[PauliZ, PauliI, PauliZ, PauliI, PauliZ, PauliI, PauliZ],
[PauliI, PauliZ, PauliZ, PauliI, PauliI, PauliZ, PauliZ],
[PauliI, PauliI, PauliI, PauliZ, PauliZ, PauliZ, PauliZ]
];
let sx = SyndromeMeasOp(MeasureStabilizerGenerators(xg, _, MeasureWithScratch));
let sz = SyndromeMeasOp(MeasureStabilizerGenerators(zg, _, MeasureWithScratch));
let code = CSS(e, d, sx, sz);
return code;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Private operation used to implement both the bit flip encoder and decoder.
///
@ -16,19 +19,23 @@ namespace Microsoft.Quantum.Canon {
///
/// # References
/// - doi:10.1103/PhysRevA.85.044302
operation BFEncoderImpl(coherentRecovery : Bool, data : Qubit[], scratch : Qubit[]) : ()
operation BFEncoderImpl (coherentRecovery : Bool, data : Qubit[], scratch : Qubit[]) : Unit
{
body {
if (coherentRecovery) {
(Controlled(X))(scratch, data[0]);
body (...)
{
if (coherentRecovery)
{
Controlled X(scratch, data[0]);
}
(Controlled(X))(data, scratch[0]);
(Controlled(X))(data, scratch[1]);
Controlled X(data, scratch[0]);
Controlled X(data, scratch[1]);
}
adjoint auto
adjoint invert;
}
/// # Summary
/// Encodes into the [3, 1, 3] / ⟦3, 1, 1⟧ bit-flip code.
///
@ -45,16 +52,14 @@ namespace Microsoft.Quantum.Canon {
///
/// # See Also
/// - Microsoft.Quantum.Canon.LogicalRegister
operation BitFlipEncoder(physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
operation BitFlipEncoder (physRegister : Qubit[], auxQubits : Qubit[]) : LogicalRegister
{
body {
BFEncoderImpl(false, physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
BFEncoderImpl(false, physRegister, auxQubits);
let logicalRegister = LogicalRegister(physRegister + auxQubits);
return logicalRegister;
}
/// # Summary
/// Decodes from the [3, 1, 3] / ⟦3, 1, 1⟧ bit-flip code.
///
@ -69,58 +74,48 @@ namespace Microsoft.Quantum.Canon {
/// # See Also
/// - Microsoft.Quantum.Canon.LogicalRegister
/// - Microsoft.Quantum.Canon.BitFlipEncoder
operation BitFlipDecoder(logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
operation BitFlipDecoder (logicalRegister : LogicalRegister) : (Qubit[], Qubit[])
{
body {
let physRegister = [logicalRegister[0]];
let auxQubits = logicalRegister[1..2];
(Adjoint BFEncoderImpl)(false, physRegister, auxQubits);
return (physRegister, auxQubits);
}
let physRegister = [(logicalRegister!)[0]];
let auxQubits = (logicalRegister!)[1 .. 2];
Adjoint BFEncoderImpl(false, physRegister, auxQubits);
return (physRegister, auxQubits);
}
/// # Summary
/// Returns a QECC value representing the ⟦3, 1, 1⟧ bit flip code encoder and
/// decoder with in-place syndrome measurement.
///
/// # Output
/// Returns an implementation of a quantum error correction code by
/// Returns an implementation of a quantum error correction code by
/// specifying a `QECC` type.
operation BitFlipCode() : QECC
operation BitFlipCode () : QECC
{
body {
let e = EncodeOp(BitFlipEncoder);
let d = DecodeOp(BitFlipDecoder);
let s = SyndromeMeasOp(MeasureStabilizerGenerators([
[PauliZ; PauliZ; PauliI];
[PauliI; PauliZ; PauliZ]
], _, MeasureWithScratch));
let code = QECC(e, d, s);
return code;
}
let e = EncodeOp(BitFlipEncoder);
let d = DecodeOp(BitFlipDecoder);
let s = SyndromeMeasOp(MeasureStabilizerGenerators([[PauliZ, PauliZ, PauliI], [PauliI, PauliZ, PauliZ]], _, MeasureWithScratch));
let code = QECC(e, d, s);
return code;
}
/// # Summary
/// Function for recovery Pauli operations for given syndrome measurement
/// by table lookup for the ⟦3, 1, 1⟧ bit flip code.
///
/// # Output
/// Function of type `RecoveryFn` that takes a syndrome measurement
/// `Result[]` and returns the `Pauli[]` operations that corrects the
/// Function of type `RecoveryFn` that takes a syndrome measurement
/// `Result[]` and returns the `Pauli[]` operations that corrects the
/// detected error.
///
/// # See Also
/// - Microsoft.Quantum.Canon.RecoveryFn
function BitFlipRecoveryFn() : RecoveryFn
function BitFlipRecoveryFn () : RecoveryFn
{
return TableLookupRecovery([
[PauliI; PauliI; PauliI];
[PauliX; PauliI; PauliI];
[PauliI; PauliI; PauliX];
[PauliI; PauliX; PauliI]
]);
return TableLookupRecovery([[PauliI, PauliI, PauliI], [PauliX, PauliI, PauliI], [PauliI, PauliI, PauliX], [PauliI, PauliX, PauliI]]);
}
}

Просмотреть файл

@ -1,11 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Syndrome measurement and the inverse of embedding.
/// $X$- and $Z$-stabilizers are not treated equally,
@ -23,43 +26,65 @@ namespace Microsoft.Quantum.Canon {
///
/// # Remarks
/// > [!WARNING]
/// > This routine is tailored
/// > This routine is tailored
/// > to a particular encoding circuit for Steane's 7 qubit code;
/// > if the encoding circuit is modified then the syndrome outcome
/// > might have to be interpreted differently.
operation _ExtractLogicalQubitFromSteaneCode(code: LogicalRegister) : (Qubit, Int, Int)
operation _ExtractLogicalQubitFromSteaneCode (code : LogicalRegister) : (Qubit, Int, Int)
{
body {
(Adjoint SteaneCodeEncoderImpl)(code[0..0], code[1..6]);
let x0 = M( code[6] );
let x1 = M( code[1] );
let x2 = M( code[3] );
mutable xsyn = 0;
if( x0 == One ) { set xsyn = xsyn ^^^ 1; }
if( x1 == One ) { set xsyn = xsyn ^^^ 2; }
if( x2 == One ) { set xsyn = xsyn ^^^ 4; }
set xsyn = xsyn - 1;
// xsyn contains the qubit index (0..6) at which a single Z-error would
// produce the given syndrome.
let z0 = M(code[5]);
let z1 = M(code[2]);
let z2 = M(code[4]);
mutable zsyn = 0;
if( z0 == One ) { set zsyn = zsyn ^^^ 1; }
if( z1 == One ) { set zsyn = zsyn ^^^ 2; }
if( z2 == One ) { set zsyn = zsyn ^^^ 5; }
set zsyn = zsyn - 1;
// zsyn contains the qubit index (0..6) at which a single X-error would
// produce the given syndrome.
return (code[0], xsyn, zsyn);
Adjoint SteaneCodeEncoderImpl((code!)[0 .. 0], (code!)[1 .. 6]);
let x0 = M((code!)[6]);
let x1 = M((code!)[1]);
let x2 = M((code!)[3]);
mutable xsyn = 0;
if (x0 == One)
{
set xsyn = xsyn ^^^ 1;
}
if (x1 == One)
{
set xsyn = xsyn ^^^ 2;
}
if (x2 == One)
{
set xsyn = xsyn ^^^ 4;
}
set xsyn = xsyn - 1;
// xsyn contains the qubit index (0..6) at which a single Z-error would
// produce the given syndrome.
let z0 = M((code!)[5]);
let z1 = M((code!)[2]);
let z2 = M((code!)[4]);
mutable zsyn = 0;
if (z0 == One)
{
set zsyn = zsyn ^^^ 1;
}
if (z1 == One)
{
set zsyn = zsyn ^^^ 2;
}
if (z2 == One)
{
set zsyn = zsyn ^^^ 5;
}
set zsyn = zsyn - 1;
// zsyn contains the qubit index (0..6) at which a single X-error would
// produce the given syndrome.
return ((code!)[0], xsyn, zsyn);
}
/// # Summary
/// Performs a $\pi / 4$ rotation about $Y$ by consuming a magic
/// state; that is, a copy of the state
@ -93,38 +118,46 @@ namespace Microsoft.Quantum.Canon {
/// This operation supports the `Adjoint` functor, in which
/// case the same magic state is consumed, but the effect
/// on the data qubit is a $-\pi/4$ $Y$-rotation.
operation InjectPi4YRotation(data: Qubit, magic: Qubit) : ()
operation InjectPi4YRotation (data : Qubit, magic : Qubit) : Unit
{
body {
(Adjoint S)(data);
body (...)
{
Adjoint S(data);
CNOT(magic, data);
S(data);
let r = MResetY(magic);
if ( r == One ) {
if (r == One)
{
// The following five gates is equal to Ry( Pi()/2.0, data)
// up to global phase.
S(data);
H(data);
(Adjoint S)(data);
Adjoint S(data);
H(data);
(Adjoint S)(data);
Adjoint S(data);
}
}
adjoint {
(Adjoint S)(data);
adjoint (...)
{
Adjoint S(data);
CNOT(magic, data);
S(data);
let r = MResetY(magic);
if ( r == Zero ) {
if (r == Zero)
{
S(data);
H(data);
S(data);
H(data);
(Adjoint S)(data);
Adjoint S(data);
}
}
}
/// # Summary
/// Given 15 approximate copies of a magic state
/// $$
@ -156,32 +189,39 @@ namespace Microsoft.Quantum.Canon {
///
/// # References
/// - [Knill](https://arxiv.org/abs/quant-ph/0402171)
operation KnillDistill( roughMagic : Qubit[] ) : ( Bool )
operation KnillDistill (roughMagic : Qubit[]) : Bool
{
body {
mutable accept = false;
using (scratch = Qubit[8]) {
let anc = scratch[7];
let code = scratch[0..6];
InjectPi4YRotation( code[0], roughMagic[14] );
SteaneCodeEncoderImpl( code[0..0], code[1..6] );
for ( idx in 0..6 ) {
(Adjoint InjectPi4YRotation)( code[idx], roughMagic[idx] );
CNOT(code[idx], anc);
InjectPi4YRotation(code[idx], roughMagic[idx + 7]);
}
let (logicalQubit, xsyn, zsyn) =
_ExtractLogicalQubitFromSteaneCode(LogicalRegister(code));
let m = M(anc);
if( xsyn == -1 && zsyn == -1 && m == Zero ) {
SWAP(logicalQubit, roughMagic[0]);
set accept = true;
}
ResetAll(scratch);
mutable accept = false;
using (scratch = Qubit[8])
{
let anc = scratch[7];
let code = scratch[0 .. 6];
InjectPi4YRotation(code[0], roughMagic[14]);
SteaneCodeEncoderImpl(code[0 .. 0], code[1 .. 6]);
for (idx in 0 .. 6)
{
Adjoint InjectPi4YRotation(code[idx], roughMagic[idx]);
CNOT(code[idx], anc);
InjectPi4YRotation(code[idx], roughMagic[idx + 7]);
}
return accept;
let (logicalQubit, xsyn, zsyn) = _ExtractLogicalQubitFromSteaneCode(LogicalRegister(code));
let m = M(anc);
if ((xsyn == -1 && zsyn == -1) && m == Zero)
{
SWAP(logicalQubit, roughMagic[0]);
set accept = true;
}
ResetAll(scratch);
}
return accept;
}
}

Просмотреть файл

@ -1,30 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Type for register of physical qubits `Qubit[]` that encode the
/// Type for register of physical qubits `Qubit[]` that encode the
/// logical qubits.
newtype LogicalRegister = Qubit[];
/// # Summary
/// Type for measurement results `Result[]` that specify an error syndrome
/// of a quantum code.
newtype Syndrome = Result[];
/// # Summary
/// Type for function that maps an error syndrome to a sequence of `Pauli[]`
/// operations that correct the detected error.
newtype RecoveryFn = (Syndrome -> Pauli[]);
// Design notes:
// These two types do not return (), such that instances of these types
// will not support autofunctors. This is inconvenient, but I think it's
// important to allow the generalization that physical and logical registers
// may have different numbers of qubits.
/// # Summary
/// Represents an operation which encodes a physical register into a
/// logical register, using the provided scratch qubits.
@ -33,7 +34,7 @@ namespace Microsoft.Quantum.Canon {
/// be encoded, while the second argument is taken to be the scratch
/// register that will be used.
newtype EncodeOp = ((Qubit[], Qubit[]) => LogicalRegister);
/// # Summary
/// Represents an operation which decodes an encoded register into a
/// physical register and the scratch qubits used to record a syndrome.
@ -41,7 +42,7 @@ namespace Microsoft.Quantum.Canon {
/// The argument to a DecodeOp is the same as the return from an
/// EncodeOp, and vice versa.
newtype DecodeOp = (LogicalRegister => (Qubit[], Qubit[]));
/// # Summary
/// Represents an operation that is used to measure the syndrome
/// of an error-correcting code block.
@ -52,13 +53,13 @@ namespace Microsoft.Quantum.Canon {
/// non–fault tolerant manner:
/// ```qsharp
/// let syndMeasOp = SyndromeMeasOp(MeasureStabilizerGenerators([
/// [PauliZ; PauliZ; PauliI];
/// [PauliI; PauliZ; PauliZ]
/// [PauliZ, PauliZ, PauliI],
/// [PauliI, PauliZ, PauliZ]
/// ], _, MeasureWithScratch));
/// ```
///
/// # Remarks
/// The signature `(LogicalRegister => Syndrome)` represents an operation
/// The signature `(LogicalRegister => Syndrome)` represents an operation
/// that acts jointly on the qubits in `LogicalRegister` and some ancilla
/// qubits followed by a measurements of the ancilla to extract a `Syndrome
/// type representing the `Result[]` of these measurements.
@ -67,16 +68,18 @@ namespace Microsoft.Quantum.Canon {
/// - Microsoft.Quantum.Canon.LogicalRegister
/// - Microsoft.Quantum.Canon.Syndrome
newtype SyndromeMeasOp = (LogicalRegister => Syndrome);
/// # Summary
/// Represents an error-correcting code as defined by its encoder,
/// decoder, and syndrome measurement procedure.
newtype QECC = (EncodeOp, DecodeOp, SyndromeMeasOp);
/// # Summary
/// Represents a Calderbank–Shor–Steane (CSS) code as defined by
/// its encoder, decoder, and its syndrome measurement procedures
/// for $X$ and $Z$ errors, respectively.
newtype CSS = (EncodeOp, DecodeOp, SyndromeMeasOp, SyndromeMeasOp);
}

144
Canon/src/Qecc/Utils.qs Normal file
Просмотреть файл

@ -0,0 +1,144 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Given an array of results, represents the array by a single
/// integer, with the 0th (leftmost) entry in the array being mapped
/// the least significant bit. Thus, [One, Zero] is represented by
/// 1 and [Zero, One] by 2.
function ResultAsInt (results : Result[]) : Int
{
mutable n = 0;
for (idxResult in 0 .. Length(results) - 1)
{
if (results[idxResult] == One)
{
set n = n + 2 ^ idxResult;
}
}
return n;
}
/// # Summary
/// Measures the given set of generators of a stabilizer group.
/// # Input
/// ## stabilizerGroup
/// An array of multiqubit Pauli operators.
/// For example, `stabilizerGroup[0]` is a list of single-qubit Pauli matrices,
/// the tensor product of which is a stabilizer generator.
/// ## logicalRegister
/// An array of qubits where the stabilizer code is defined.
/// ## gadget
/// An operation that specifies how to measure a multiqubit Pauli operator.
/// # Output
/// The result of measurements.
/// # Remarks
/// This does not check if the given set of generators are commuting.
/// If they are not commuting, the result of measurements may be arbitrary.
operation MeasureStabilizerGenerators (stabilizerGroup : Pauli[][], logicalRegister : LogicalRegister, gadget : ((Pauli[], Qubit[]) => Result)) : Syndrome
{
let results = MeasurePaulis(stabilizerGroup, logicalRegister!, gadget);
return Syndrome(results);
}
/// # Summary
/// Performs a single round of error correction by a quantum code
/// described by a `QECC` type.
///
/// # Input
/// ## code
/// A quantum error-correcting code packaged as a `QECC` type describes
/// the encoding and deconding of quantum data, and how error syndromes
/// are to be measuremed.
/// ## fn
/// A `RecoveryFn` that maps each error syndrome to the `Pauli[]` operations
/// that correct the detected error.
/// ## logicalRegister
/// An array of qubits where the stabilizer code is defined.
///
/// # See Also
/// - Microsoft.Quantum.Canon.QECC
/// - Microsoft.Quantum.Canon.RecoveryFn
/// - Microsoft.Quantum.Canon.LogicalRegister
operation Recover (code : QECC, fn : RecoveryFn, logicalRegister : LogicalRegister) : Unit
{
let (encode, decode, syndMeas) = code!;
let syndrome = syndMeas!(logicalRegister);
let recoveryOp = fn!(syndrome);
ApplyPauli(recoveryOp, logicalRegister!);
}
/// # Summary
/// Performs a single round of error correction by a quantum code
/// described by a `CSS` type.
///
/// # Input
/// ## code
/// A quantum CSS error-correcting code packaged as a `CSS` type describes
/// the encoding and deconding of quantum data, and how error syndromes
/// are to be measuremed.
/// ## fnX
/// A `RecoveryFn` that maps each $X$ error syndrome to the `Pauli[]` operations
/// that correct the detected error.
/// ## fnZ
/// A `RecoveryFn` that maps each $Z$ error syndrome to the `Pauli[]` operations
/// that correct the detected error.
/// ## logicalRegister
/// An array of qubits where the stabilizer code is defined.
///
/// # See Also
/// - Microsoft.Quantum.Canon.CSS
/// - Microsoft.Quantum.Canon.RecoveryFn
/// - Microsoft.Quantum.Canon.LogicalRegister
operation RecoverCSS (code : CSS, fnX : RecoveryFn, fnZ : RecoveryFn, logicalRegister : LogicalRegister) : Unit
{
let (encode, decode, syndMeasX, syndMeasZ) = code!;
let syndromeX = syndMeasX!(logicalRegister);
let recoveryOpX = fnX!(syndromeX);
Message($"X: {syndromeX} → {recoveryOpX}");
ApplyPauli(recoveryOpX, logicalRegister!);
let syndromeZ = syndMeasZ!(logicalRegister);
let recoveryOpZ = fnZ!(syndromeZ);
Message($"Z: {syndromeZ} → {recoveryOpZ}");
ApplyPauli(recoveryOpZ, logicalRegister!);
}
function TableLookupRecoveryImpl (table : Pauli[][], syndrome : Syndrome) : Pauli[]
{
return table[ResultAsInt(syndrome!)];
}
/// # Summary
/// For a given table of Pauli operations on a given register of qubits, this function
/// returns an object of type `RecoveryFn` which contains all information needed to
/// perform a table-lookup decoding with respect to the given array of Pauli operations.
///
/// # Input
/// ## table
/// Table of Pauli operations that operate on a given qubit register
///
/// # Output
/// An object of type `RecoveryFn`, i.e., a map `Syndrome -> Pauli[]` that associates
/// with a given syndrome array a corresponding Pauli correction operation.
function TableLookupRecovery (table : Pauli[][]) : RecoveryFn
{
return RecoveryFn(TableLookupRecoveryImpl(table, _));
}
}

Просмотреть файл

@ -1,15 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
// A simulation technique converts an EvolutionGenerator to time evolution
// by the encoded system for some time step
// Here is an example of a simulation technique.
// Here is an example of a simulation technique.
/// # Summary
/// Implements time-evolution by a term contained in a `GeneratorSystem`.
///
@ -17,33 +20,37 @@ namespace Microsoft.Quantum.Canon {
/// ## evolutionGenerator
/// A complete description of the system to be simulated.
/// ## idx
/// Integer index to a term in the described system.
/// Integer index to a term in the described system.
/// ## stepsize
/// Multiplier on duration of time-evolution by term indexed by `idx`.
/// ## qubits
/// Qubits acted on by simulation.
operation TrotterStepImpl(evolutionGenerator: EvolutionGenerator, idx : Int, stepsize: Double, qubits: Qubit[]) : () {
body {
let (evolutionSet, generatorSystem) = evolutionGenerator;
let (nTerms, generatorSystemFunction) = generatorSystem;
operation TrotterStepImpl (evolutionGenerator : EvolutionGenerator, idx : Int, stepsize : Double, qubits : Qubit[]) : Unit
{
body (...)
{
let (evolutionSet, generatorSystem) = evolutionGenerator!;
let (nTerms, generatorSystemFunction) = generatorSystem!;
let generatorIndex = generatorSystemFunction(idx);
(evolutionSet(generatorIndex))(stepsize, qubits);
(evolutionSet!(generatorIndex))!(stepsize, qubits);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implements a single time-step of time-evolution by the system
/// described in an `EvolutionGenerator` using a Trotter–Suzuki
/// Implements a single time-step of time-evolution by the system
/// described in an `EvolutionGenerator` using a Trotter–Suzuki
/// decomposition.
///
/// # Input
/// ## evolutionGenerator
/// A complete description of the system to be simulated.
/// ## trotterOrder
/// Order of Trotter integrator. Order 1 and 2 are currently supported.
/// Order of Trotter integrator. This must be either 1 or an even number.
/// ## trotterStepSize
/// Duration of simulated time-evolution in single Trotter step.
///
@ -54,21 +61,23 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// For more on the Trotter–Suzuki decomposition, see
/// [Time-Ordered Composition](/quantum/libraries/control-flow#time-ordered-composition).
function TrotterStep(evolutionGenerator: EvolutionGenerator, trotterOrder: Int, trotterStepSize: Double) : (Qubit[] => () : Adjoint, Controlled)
function TrotterStep (evolutionGenerator : EvolutionGenerator, trotterOrder : Int, trotterStepSize : Double) : (Qubit[] => Unit : Adjoint, Controlled)
{
let (evolutionSet, generatorSystem) = evolutionGenerator;
let (nTerms, generatorSystemFunction) = generatorSystem;
let (evolutionSet, generatorSystem) = evolutionGenerator!;
let (nTerms, generatorSystemFunction) = generatorSystem!;
// The input to DecomposeIntoTimeStepsCA has signature
// (Int, ((Int, Double, Qubit[]) => () : Adjoint, Controlled))
let trotterForm = (nTerms, TrotterStepImpl(evolutionGenerator, _, _, _));
return (DecomposeIntoTimeStepsCA(trotterForm,trotterOrder))(trotterStepSize, _);
return (DecomposeIntoTimeStepsCA(trotterForm, trotterOrder))(trotterStepSize, _);
}
// This simulation algorithm takes (timeMax, EvolutionGenerator,
// This simulation algorithm takes (timeMax, EvolutionGenerator,
// register) and other algorithm-specific parameters (trotterStepSize,
// trotterOrder), and performs evolution under the EvolutionGenerator
// for time = timeMax.
/// # Summary
/// Makes repeated calls to `TrotterStep` to approximate the
/// time-evolution operator $e^{-i H t}$.
@ -77,90 +86,92 @@ namespace Microsoft.Quantum.Canon {
/// ## trotterStepSize
/// Duration of simulated time-evolution in single Trotter step.
/// ## trotterOrder
/// Order of Trotter integrator. Order 1 and 2 are currently supported.
/// Order of Trotter integrator. This must be either 1 or an even number.
/// ## maxTime
/// Total duration of simulation $t$.
/// ## evolutionGenerator
/// A complete description of the system to be simulated.
/// ## qubits
/// Qubits acted on by simulation.
operation TrotterSimulationAlgorithmImpl(trotterStepSize: Double,
trotterOrder: Int,
maxTime: Double,
evolutionGenerator: EvolutionGenerator,
qubits:Qubit[]) : () {
body{
operation TrotterSimulationAlgorithmImpl (trotterStepSize : Double, trotterOrder : Int, maxTime : Double, evolutionGenerator : EvolutionGenerator, qubits : Qubit[]) : Unit
{
body (...)
{
let nTimeSlices = Ceiling(maxTime / trotterStepSize);
let resizedTrotterStepSize = maxTime / ToDouble(nTimeSlices);
for (idxTimeSlice in 0..nTimeSlices-1) {
for (idxTimeSlice in 0 .. nTimeSlices - 1)
{
(TrotterStep(evolutionGenerator, trotterOrder, resizedTrotterStepSize))(qubits);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// `SimulationAlgorithm` function that uses a Trotter–Suzuki
/// `SimulationAlgorithm` function that uses a Trotter–Suzuki
/// decomposition to approximate the time-evolution operator $e^{-i H t}$.
///
/// # Input
/// ## trotterStepSize
/// Duration of simulated time-evolution in single Trotter step.
/// Duration of simulated time-evolution in single Trotter step.
/// ## trotterOrder
/// Order of Trotter integrator. Order 1 and 2 are currently supported.
/// Order of Trotter integrator. This must be either 1 or an even number.
///
/// # Output
/// A `SimulationAlgorithm` type.
function TrotterSimulationAlgorithm(trotterStepSize: Double,
trotterOrder: Int) : SimulationAlgorithm
function TrotterSimulationAlgorithm (trotterStepSize : Double, trotterOrder : Int) : SimulationAlgorithm
{
return SimulationAlgorithm(TrotterSimulationAlgorithmImpl(trotterStepSize,trotterOrder, _, _, _));
return SimulationAlgorithm(TrotterSimulationAlgorithmImpl(trotterStepSize, trotterOrder, _, _, _));
}
// This simple time-dependent simulation algorithm implements a
// sequence of uniformly-sized trotter steps
// This simple time-depedendent simulation algorithm implements a
// sequence of uniformly-sized trotter steps
/// # Summary
/// Implementation of multiple Trotter steps to approximate a unitary
/// operator that solves the time-dependent Schr<68>dinger equation at time
/// $t$.
/// Implementation of multiple Trotter steps to approximate a unitary
/// operator that solves the time-dependent Schr<68>dinger equation at time
/// $t$.
///
/// # Input
/// ## trotterStepSize
/// Duration of simulated time-evolution in single Trotter step.
/// Duration of simulated time-evolution in single Trotter step.
/// ## trotterOrder
/// Order of Trotter integrator. Order 1 and 2 are currently supported.
/// Order of Trotter integrator. This must be either 1 or an even number.
/// ## maxTime
/// Total duration of simulation $t$.
/// ## evolutionSchedule
/// A complete description of the time-dependent system to be simulated.
/// ## qubits
/// Qubits acted on by simulation.
operation TimeDependentTrotterSimulationAlgorithmImpl( trotterStepSize: Double,
trotterOrder: Int,
maxTime: Double,
evolutionSchedule: EvolutionSchedule,
qubits:Qubit[]) : () {
body {
operation TimeDependentTrotterSimulationAlgorithmImpl (trotterStepSize : Double, trotterOrder : Int, maxTime : Double, evolutionSchedule : EvolutionSchedule, qubits : Qubit[]) : Unit
{
body (...)
{
let nTimeSlices = Ceiling(maxTime / trotterStepSize);
let resizedTrotterStepSize = maxTime / ToDouble(nTimeSlices);
for(idxTimeSlice in 0..nTimeSlices-1){
for (idxTimeSlice in 0 .. nTimeSlices - 1)
{
let schedule = ToDouble(idxTimeSlice) / ToDouble(nTimeSlices);
let (evolutionSet, generatorSystemTimeDependent) = evolutionSchedule;
let (evolutionSet, generatorSystemTimeDependent) = evolutionSchedule!;
let generatorSystem = generatorSystemTimeDependent(schedule);
let evolutionGenerator = EvolutionGenerator(evolutionSet, generatorSystem);
(TrotterSimulationAlgorithm(resizedTrotterStepSize, trotterOrder))(resizedTrotterStepSize, evolutionGenerator, qubits);
(TrotterSimulationAlgorithm(resizedTrotterStepSize, trotterOrder))!(resizedTrotterStepSize, evolutionGenerator, qubits);
}
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// `TimeDependentSimulationAlgorithm` function that uses a Trotter–Suzuki
/// decomposition to approximate a unitary operator that solves the
@ -170,14 +181,15 @@ namespace Microsoft.Quantum.Canon {
/// ## trotterStepSize
/// Duration of simulated time-evolution in single Trotter step.
/// ## trotterOrder
/// Order of Trotter integrator. Order 1 and 2 are currently supported.
/// Order of Trotter integrator. This must be either 1 or an even number.
///
/// # Output
/// A `TimeDependentSimulationAlgorithm` type.
function TimeDependentTrotterSimulationAlgorithm( trotterStepSize: Double,
trotterOrder: Int) : TimeDependentSimulationAlgorithm {
return TimeDependentSimulationAlgorithm(TimeDependentTrotterSimulationAlgorithmImpl(trotterStepSize,trotterOrder, _, _, _));
function TimeDependentTrotterSimulationAlgorithm (trotterStepSize : Double, trotterOrder : Int) : TimeDependentSimulationAlgorithm
{
return TimeDependentSimulationAlgorithm(TimeDependentTrotterSimulationAlgorithmImpl(trotterStepSize, trotterOrder, _, _, _));
}
}

Просмотреть файл

@ -0,0 +1,261 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
// This library defines types for block-encoding an arbitrary operator.
// General operations for performing block-encoding are provided,
// together with operations for creating a quantum walk from This
// block-encoding.
/// # Summary
/// A `BlockEncoding` is a unitary $U$ where an arbitrary operator $H$ of
/// interest that acts on the system register `s` is encoded in the top-
/// left block corresponding to auxiliary state `\ket{0}_a`. That is,
///
/// $$
/// \begin{align}
/// (\bra{0}_a\otimes I_s)U(\ket{0}_a\otimes I_s) = H
/// \end{align}
/// $$.
///
/// # Input
/// ## First Parameter
/// An array of qubits representing the auxiliary register acted on by $U$.
/// The action of $U$ is only defined when this is $\ket{0}_a$.
/// ## Second Parameter
/// An array of qubits representing the system register acted on by $H$.
///
/// # Output
/// A unitary $U$ acting jointly on registers `a` and `s` that block-
/// encodes $H$.
newtype BlockEncoding = ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// A `BlockEncodingReflection` is a unitary $U$ with the same properties
/// as a `BlockEncoding`, but is also a reflection. That is,
/// $U^\dag = U$.
///
/// # Input
/// ## First Parameter
/// An array of qubits representing the auxiliary register acted on by $U$.
/// The action of $U$ is only defined when this is $\ket{0}_a$.
/// ## Second Parameter
/// An array of qubits representing the system register acted on by $H$.
///
/// # Output
/// A unitary $U$ acting jointly on registers `a` and `s` that block-
/// encodes $H$.
///
/// # See Also
/// - Microsoft.Quantum.Canon.BlockEncoding
newtype BlockEncodingReflection = BlockEncoding;
/// # Summary
/// A `TimeDependentBlockEncoding` is a unitary $U$ controlled by a state
/// $\ket{k}_d$ in clock register `d` such that an arbitrary operator $H_k$ of
/// interest that acts on the system register `s` is encoded in the top-
/// left block corresponding to auxiliary state `\ket{0}_a`. That is,
///
/// $$
/// \begin{align}
/// (\bra{0}_a\otimes I_{ds})U(\ket{0}_a\otimes I_{ds}) = \sum_{k}\ket{k}\bra{k}_d\otimes H_k.
/// \end{align}
/// $$.
///
/// # Input
/// ## First Parameter
/// An array of qubits representing the time register that controls $H_k$.
/// ## Second Parameter
/// An array of qubits representing the auxiliary register acted on by $U$.
/// The action of $U$ is only defined when this is $\ket{0}_a$.
/// ## This Parameter
/// An array of qubits representing the system register acted on by $H$.
///
/// # Output
/// A unitary $U$ acting jointly on registers `d`, `a`, and `s` that block-
/// encodes $H_k$.
newtype TimeDependentBlockEncoding = ((Qubit[], Qubit[], Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// This function converts a `BlockEncoding` unitary $U$ that encodes some
/// operator $H$ of interest into a `BlockEncodingReflection` $U'$ that
/// encodes the same operator, but also satisfies $U'^\dag = U'$.
/// This increases the size of the auxiliary register of $U$ by one qubit.
///
/// # Input
/// ## blockEncoding
/// A `BlockEncoding` unitary $U$ to be converted into a reflection.
///
/// # Output
/// A unitary $U'$ acting jointly on registers `a` and `s` that block-
/// encodes $H$, and satisfies $U'^\dag = U'$.
///
/// # Remarks
/// This increases the size of the auxiliary register of $U$ by one qubit.
///
/// # References
/// - Hamiltonian Simulation by Qubitization
/// Guang Hao Low, Isaac L. Chuang
/// https://arxiv.org/abs/1610.06546
///
/// # See Also
/// - Microsoft.Quantum.Canon.BlockEncoding
/// - Microsoft.Quantum.Canon.BlockEncodingReflection
function BlockEncodingToReflection(blockEncoding: BlockEncoding) : BlockEncodingReflection
{
return BlockEncodingReflection(BlockEncoding(BlockEncodingToReflection_(blockEncoding, _, _)));
}
/// # Summary
/// Implementation of `BlockEncodingToReflection`.
operation BlockEncodingToReflection_(blockEncoding: BlockEncoding, auxiliary: Qubit[], system: Qubit[]) : Unit {
body (...) {
let prep = auxiliary[0];
let blockEncodingAncilla = Rest(auxiliary);
let op1 = Controlled blockEncoding!(_, (blockEncodingAncilla, system));
let op0 = ApplyToEachCA(H,_);
WithCA(op0, WithCA(op1, ApplyToEachCA(X,_), _), [prep]);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This function converts a `BlockEncodingReflection` unitary $U$
/// that encodes some operator $H$ of interest into a quantum walk
/// $W$ containing the spectrum of $\pm e^{\pm i\sin^{-1}(H)}$.
///
/// # Input
/// ## blockEncodingReflection
/// A `BlockEncodingReflection` unitary $U$ to be converted into a Quantum
/// walk.
///
/// # Output
/// A quantum walk $W$ acting jointly on registers `a` and `s` that block-
/// encodes $H$, and contains the spectrum of $\pm e^{\pm i\sin^{-1}(H)}$.
///
/// # References
/// - Hamiltonian Simulation by Qubitization
/// Guang Hao Low, Isaac L. Chuang
/// https://arxiv.org/abs/1610.06546
///
/// # See Also
/// - Microsoft.Quantum.Canon.BlockEncoding
/// - Microsoft.Quantum.Canon.BlockEncodingReflection
function QuantumWalkByQubitization(blockEncoding: BlockEncodingReflection) : ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled) {
return QuantumWalkByQubitization_(blockEncoding, _, _);
}
/// # Summary
/// Implementation of `Qubitization`.
operation QuantumWalkByQubitization_(blockEncoding: BlockEncodingReflection, auxiliary: Qubit[], system: Qubit[]) : Unit {
body (...){
Exp([PauliI], -0.5 * PI(), [system[0]]);
RAll0(PI(), auxiliary);
// NB: We unwrap twice here, since BlockEncodingReflection wraps BlockEncoding.
blockEncoding!!(auxiliary, system);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This constructs a `BlockEncoding` unitary $U=P\cdot V\cdot P^\dag$ that encodes some
/// operator $H=\sum_{j}|\alpha_j|U_j$ of interest that is a linear combination of
/// unitaries. Typically, $P$ is a state preparation unitary such that
/// $P\ket{0}_a=\sum_j\sqrt{\alpha_j/\|\vec\alpha\|_2}\ket{j}_a$,
/// and $V=\sum_{j}\ket{j}\bra{j}_a\otimes U_j$.
///
/// # Input
/// ## statePreparation
/// A unitary $P$ that prepares some target state.
/// ## selector
/// A unitary $V$ that encodes the component unitaries of $H$.
///
/// # Output
/// A unitary $U$ acting jointly on registers `a` and `s` that block-
/// encodes $H$, and satisfies $U^\dag = U$.
///
/// # Remarks
/// This `BlockEncoding` implementation gives it the properties of a
/// `BlockEncodingReflection`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.BlockEncoding
/// - Microsoft.Quantum.Canon.BlockEncodingReflection
function BlockEncodingByLCU<'T,'S>(
statePreparation: ('T => Unit : Adjoint, Controlled),
selector: (('T, 'S) => Unit : Adjoint, Controlled))
: (('T, 'S) => Unit : Adjoint, Controlled) {
return BlockEncodingByLCU_(statePreparation, selector, _, _);
}
/// # Summary
/// Implementation of `BlockEncodingByLCU`.
operation BlockEncodingByLCU_<'T,'S>(
statePreparation: ('T => Unit : Adjoint, Controlled),
selector: (('T, 'S) => Unit : Adjoint, Controlled),
auxiliary: 'T,
system: 'S)
: Unit {
body (...){
WithCA(statePreparation, selector(_, system), auxiliary);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// This constructs a `BlockEncodingReflection` unitary $U=P\cdot V\cdot P^\dag$ that encodes some
/// operator $H=\sum_{j}|\alpha_j|U_j$ of interest that is a linear combination of
/// unitaries. Typically, $P$ is a state preparation unitary such that
/// $P\ket{0}_a\sum_j\sqrt{\alpha_j/\|\vec\alpha\|_2}\ket{j}_a$,
/// and $V=\sum_{j}\ket{j}\bra{j}_a\otimes U_j$.
///
/// # Input
/// ## statePreparation
/// A unitary $P$ that prepares some target state.
/// ## selector
/// A unitary $V$ that encodes the component unitaries of $H$.
///
/// # Output
/// A unitary $U$ acting jointly on registers `a` and `s` that block-
/// encodes $H$, and satisfies $U'^{-1} = U$.
///
/// # Remarks
/// This `BlockEncoding` implementation gives it the properties of a
/// `BlockEncodingReflection`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.BlockEncoding
/// - Microsoft.Quantum.Canon.BlockEncodingReflection
function BlockEncodingReflectionByLCU(
statePreparation: (Qubit[] => Unit : Adjoint, Controlled),
selector: ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled)
) : BlockEncodingReflection {
return BlockEncodingToReflection(BlockEncoding(BlockEncodingByLCU(statePreparation, selector)));
}
/// # Summary
/// Conversion of ((BigEndian, Qubit[]) => () : Adjoint, Controlled) to BlockEncoding
operation BlockEncodingFromBEandQubit_(
op: ((BigEndian, Qubit[]) => Unit : Adjoint, Controlled),
auxiliary: Qubit[],
system: Qubit[]) : Unit
{
body (...) {
op(BigEndian(auxiliary), system);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
}

Просмотреть файл

@ -1,21 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
// Convention for GeneratorIndex = ((Int[],Double[]), Int[])
// We index single Paulis as 0 for I, 1 for X, 2 for Y, 3 for Z.
// We index Pauli strings with arrays of integers e.g. a = [3;1;1;2] for ZXXY.
// We index Pauli strings with arrays of integers e.g. a = [3,1,1,2] for ZXXY.
// We assume the zeroth element of Double[] is the angle of rotation
// We index the qubits that Pauli strings act on with arrays of integers e.g. q = [2;4;5;8] for Z_2 X_4 X_5, Y_8
// We index the qubits that Pauli strings act on with arrays of integers e.g. q = [2,4,5,8] for Z_2 X_4 X_5, Y_8
// An example of a Pauli string GeneratorIndex is thus ((a,b), q)
// Consider the Hamiltonian H = 0.1 XI + 0.2 IX + 0.3 ZY
// Its GeneratorTerms are (([1],b),[0]), 0.1), (([1],b),[1]), 0.2), (([3;2],b),[0;1]), 0.3).
// Its GeneratorTerms are (([1],b),[0]), 0.1), (([1],b),[1]), 0.2), (([3,2],b),[0,1]), 0.3).
/// # Summary
/// Converts a integer to a single-qubit Pauli operator.
///
@ -24,14 +26,16 @@ namespace Microsoft.Quantum.Canon {
/// Integer in the range `0..3` to be converted to Pauli operators.
///
/// # Output
/// A `Pauli` operator given by `[PauliI; PauliX; PauliY; PauliZ][idx]`.
function IntToPauli(idx : Int) : Pauli {
let paulis = [PauliI; PauliX; PauliY; PauliZ];
/// A `Pauli` operator given by `[PauliI, PauliX, PauliY, PauliZ][idx]`.
function IntToPauli (idx : Int) : Pauli
{
let paulis = [PauliI, PauliX, PauliY, PauliZ];
return paulis[idx];
}
/// # Summary
/// Converts an array of integers to an array of single-qubit Pauli
/// Converts an array of integers to an array of single-qubit Pauli
/// operators.
///
/// # Input
@ -40,21 +44,25 @@ namespace Microsoft.Quantum.Canon {
/// operators.
///
/// # Output
/// An array `paulis` of Pauli operators `Pauli[]` the same length as
/// An array `paulis` of Pauli operators `Pauli[]` the same length as
/// `ints` such that `paulis[idxPauli]` is equal to the element of
/// `[PauliI; PauliX; PauliY; PauliZ]` given by `ints[idxPauli]`.
function IntsToPaulis(ints : Int[]) : Pauli[] {
/// `[PauliI, PauliX, PauliY, PauliZ]` given by `ints[idxPauli]`.
function IntsToPaulis (ints : Int[]) : Pauli[]
{
let nInts = Length(ints);
mutable paulis = new Pauli[nInts];
for (idxInt in 0..nInts - 1){
for (idxInt in 0 .. nInts - 1)
{
set paulis[idxInt] = IntToPauli(ints[idxInt]);
}
return paulis;
}
/// # Summary
/// Represents a dynamical generator as a set of simulatable gates and an
/// Represents a dynamical generator as a set of simulatable gates and an
/// expansion in the Pauli basis.
///
/// See [Dynamical Generator Modeling](/quantum/libraries/data-structures#dynamical-generator-modeling)
@ -65,24 +73,26 @@ namespace Microsoft.Quantum.Canon {
/// A generator index to be represented as unitary evolution in the Pauli
/// basis.
/// ## delta
/// A multiplier on the duration of time-evolution by the term referenced
/// A multiplier on the duration of time-evolution by the term referenced
/// in `generatorIndex`.
/// ## qubits
/// Register acted upon by time-evolution operator.
operation PauliEvolutionImpl(generatorIndex : GeneratorIndex, delta : Double, qubits: Qubit[]) : ()
operation PauliEvolutionImpl (generatorIndex : GeneratorIndex, delta : Double, qubits : Qubit[]) : Unit
{
body {
let ((idxPaulis, idxDoubles), idxQubits) = generatorIndex;
body (...)
{
let ((idxPaulis, idxDoubles), idxQubits) = generatorIndex!;
let pauliString = IntsToPaulis(idxPaulis);
let op = Exp(pauliString, delta * idxDoubles[0], _);
(RestrictToSubregisterCA(op, idxQubits))(qubits);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Represents a dynamical generator as a set of simulatable gates and an
/// expansion in the Pauli basis.
@ -95,11 +105,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// An `EvolutionUnitary` representing time-evolution by the term
/// referenced in `generatorIndex.
function PauliEvolutionFunction(generatorIndex : GeneratorIndex) : EvolutionUnitary
function PauliEvolutionFunction (generatorIndex : GeneratorIndex) : EvolutionUnitary
{
return EvolutionUnitary(PauliEvolutionImpl(generatorIndex, _, _));
}
/// # Summary
/// Represents a dynamical generator as a set of simulatable gates and an
/// expansion in the Pauli basis.
@ -111,9 +122,11 @@ namespace Microsoft.Quantum.Canon {
/// # Remarks
/// This is obtained by partial application of
/// <xref:microsoft.quantum.canon.paulievolutionfunction>.
function PauliEvolutionSet() : EvolutionSet
function PauliEvolutionSet () : EvolutionSet
{
return EvolutionSet(PauliEvolutionFunction);
}
}

Просмотреть файл

@ -0,0 +1,155 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
/// # Summary
/// Extracts the coefficient of a Pauli term described by a `GeneratorIndex`.
///
/// # Input
/// ## generatorIndex
/// `GeneratorIndex` type that encodes a Pauli term.
///
/// # Output
/// The coefficient of the term described by a `GeneratorIndex`.
function PauliCoefficientFromGenIdx(generatorIndex: GeneratorIndex) : Double {
let ((idxPaulis, coeff), idxQubits) = generatorIndex!;
return coeff[0];
}
/// # Summary
/// Extracts the Pauli string and its qubit indices of a Pauli term described
/// by a `GeneratorIndex`.
///
/// # Input
/// ## generatorIndex
/// `GeneratorIndex` type that encodes a Pauli term.
///
/// # Output
/// The Pauli string of the term described by a `GeneratorIndex`, and
/// indices to the qubits it acts on.
function PauliStringFromGenIdx(generatorIndex: GeneratorIndex) : (Pauli[], Int[]) {
let ((idxPaulis, coeff), idxQubits) = generatorIndex!;
return (IntsToPaulis(idxPaulis), idxQubits);
}
/// # Summary
/// Creates a block-encoding unitary $U$ of the Hamiltonian $H=\sum_{j}\alpha_j P_j$ described by a
/// sum of Pauli terms $P_j$, each with real coefficient $\alpha_j$.
///
/// # Input
/// ## generatorSystem
/// A `GeneratorSystem` that describes $H$ as a sum of Pauli terms
///
/// # Output
/// ## First parameter
/// The one-norm of coefficients $\alpha=\sum_{j}|\alpha_j|$.
/// ## Second parameter
/// A `BlockEncodingReflection` unitary $U$ of the Hamiltonian $U$. As this unitary
/// satisfies $U^2 = I$, it is also a reflection.
///
/// # Remarks
/// This is obtained by preparing and unpreparing the state $\sum_{j}\sqrt{\alpha_j/\alpha}\ket{j}$,
/// and constructing a multiply-controlled unitary
/// <xref:microsoft.quantum.canon.statepreparationpositivecoefficients> and
/// <xref:microsoft.quantum.canon.multiplexoperationsfromgenerator>.
function PauliBlockEncoding(generatorSystem: GeneratorSystem) : (Double, BlockEncodingReflection) {
let statePrepUnitary = StatePreparationPositiveCoefficients;
let multiplexer = MultiplexerFromGenerator;
return PauliBlockEncodingImpl(generatorSystem, statePrepUnitary, multiplexer);
}
/// # Summary
/// Creates a block-encoding unitary $U$ of the Hamiltonian $H=\sum_{j}\alpha_j P_j$ described by a
/// sum of Pauli terms $P_j$, each with real coefficient $\alpha_j$.
///
/// # Input
/// ## generatorSystem
/// A `GeneratorSystem` that describes $H$ as a sum of Pauli terms
/// ## statePrepUnitary
/// A unitary operation $P$ that prepares $P\ket{0}=\sum_{j}\sqrt{\alpha_j}\ket{j}$ given
/// an array of coefficients $\{\sqrt{\alpha}_j\}$.
/// ## statePrepUnitary
/// A unitary operation $V$ that applies the unitary $V_j$ controlled on index $\ket{j}$,
/// given a function $f: j\rightarrow V_j$.
///
/// # Output
/// ## First parameter
/// The one-norm of coefficients $\alpha=\sum_{j}|\alpha_j|$.
/// ## Second parameter
/// A `BlockEncodingReflection` unitary $U$ of the Hamiltonian $U$. As this unitary
/// satisfies $U^2 = I$, it is also a reflection.
///
/// # Remarks
/// Example operations the prepare and unpreparing the state $\sum_{j}\sqrt{\alpha_j/\alpha}\ket{j}$,
/// and construct a multiply-controlled unitary are
/// <xref:microsoft.quantum.canon.statepreparationpositivecoefficients> and
/// <xref:microsoft.quantum.canon.multiplexoperationsfromgenerator>.
function PauliBlockEncodingImpl(
generatorSystem: GeneratorSystem,
statePrepUnitary: (Double[] -> (BigEndian => Unit : Adjoint, Controlled)),
multiplexer: ((Int, (Int -> (Qubit[] => Unit : Adjoint, Controlled))) -> ((BigEndian, Qubit[]) => Unit : Adjoint, Controlled))) : (Double, BlockEncodingReflection) {
let (nTerms, intToGenIdx) = generatorSystem!;
let op = IdxToCoeff_(_, intToGenIdx, PauliCoefficientFromGenIdx);
let coefficients = Map(op, IntArrayFromRange(0..nTerms-1));
let oneNorm = PowD(PNorm(2.0, coefficients),2.0);
let unitaryGenerator = (nTerms, IdxToUnitary_(_, intToGenIdx, PauliLCUUnitary_));
let statePreparation = statePrepUnitary(coefficients);
let selector = multiplexer(unitaryGenerator);
let blockEncoding = BlockEncodingReflection(BlockEncoding(BlockEncodingFromBEandQubit_(BlockEncodingByLCU(statePreparation, selector),_,_)));
return (oneNorm, blockEncoding);
}
/// # Summary
/// Used in implementation of `PauliBlockEncoding`
/// # See Also
/// - Microsoft.Quantum.Canon.PauliBlockEncoding
function IdxToCoeff_(idx: Int, genFun: (Int -> GeneratorIndex), genIdxToCoeff: (GeneratorIndex -> Double)) : Double {
return Sqrt(AbsD(genIdxToCoeff(genFun(idx))));
}
/// # Summary
/// Used in implementation of `PauliBlockEncoding`
/// # See Also
/// - Microsoft.Quantum.Canon.PauliBlockEncoding
function IdxToUnitary_(idx: Int, genFun: (Int -> GeneratorIndex), genIdxToUnitary: (GeneratorIndex -> (Qubit[] => Unit : Adjoint, Controlled))) : (Qubit[] => Unit : Adjoint, Controlled) {
return genIdxToUnitary(genFun(idx));
}
/// # Summary
/// Used in implementation of `PauliBlockEncoding`
/// # See Also
/// - Microsoft.Quantum.Canon.PauliBlockEncoding
function PauliLCUUnitary_(generatorIndex: GeneratorIndex) : (Qubit[] => Unit : Adjoint, Controlled) {
return ApplyPauliLCUUnitary_(generatorIndex,_);
}
/// # Summary
/// Used in implementation of `PauliBlockEncoding`
/// # See Also
/// - Microsoft.Quantum.Canon.PauliBlockEncoding
operation ApplyPauliLCUUnitary_(generatorIndex: GeneratorIndex, qubits: Qubit[]) : Unit {
body (...) {
let ((idxPaulis, coeff), idxQubits) = generatorIndex!;
let pauliString = IntsToPaulis(idxPaulis);
let pauliQubits = Subarray(idxQubits, qubits);
ApplyPauli(pauliString, pauliQubits);
if(coeff[0] < 0.0){
// -1 phase
Exp([PauliI], PI(), [pauliQubits[0]]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
}

Просмотреть файл

@ -1,12 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// This interpolates between two generators with a uniform schedule,
/// returning an operation that applies simulated evolution under
@ -27,26 +30,22 @@ namespace Microsoft.Quantum.Canon {
/// If the interpolation time is chosen to meet the adiabatic conditions,
/// then this function returns an operation which performs adiabatic
/// state preparation for the final dynamical generator.
function InterpolatedEvolution( interpolationTime: Double,
evolutionGeneratorStart: EvolutionGenerator,
evolutionGeneratorEnd: EvolutionGenerator,
timeDependentSimulationAlgorithm: TimeDependentSimulationAlgorithm)
: (Qubit[] => () : Adjoint, Controlled) {
function InterpolatedEvolution (inerpolationTime : Double, evolutionGeneratorStart : EvolutionGenerator, evolutionGeneratorEnd : EvolutionGenerator, timeDependentSimulationAlgorithm : TimeDependentSimulationAlgorithm) : (Qubit[] => Unit : Adjoint, Controlled)
{
// evolutionSetStart and evolutionSetEnd must be identical
let (evolutionSetStart, generatorSystemStart) = evolutionGeneratorStart;
let (evolutionSetEnd, generatorSystemEnd) = evolutionGeneratorEnd;
let (evolutionSetStart, generatorSystemStart) = evolutionGeneratorStart!;
let (evolutionSetEnd, generatorSystemEnd) = evolutionGeneratorEnd!;
let generatorSystemTimeDependent = InterpolateGeneratorSystems(generatorSystemStart, generatorSystemEnd);
let evolutionSchedule = EvolutionSchedule(evolutionSetStart, generatorSystemTimeDependent);
return timeDependentSimulationAlgorithm(interpolationTime, evolutionSchedule, _);
let evolutionSchedule = EvolutionSchedule(evolutionSetStart, generatorSystemTimeDependent!);
return timeDependentSimulationAlgorithm!(inerpolationTime, evolutionSchedule, _);
}
/// # Summary
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on the input state, followed by adiabatic state
/// preparation using a `adiabaticUnitary`, and finally phase estimation
/// with respect to `qpeUnitary`on the resulting state using a
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on the input state, followed by adiabatic state
/// preparation using a `adiabaticUnitary`, and finally phase estimation
/// with respect to `qpeUnitary`on the resulting state using a
/// `phaseEstAlgorithm`.
///
/// # Input
@ -70,24 +69,20 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// An estimate $\hat{\phi}$ of the ground state energy $\phi$
/// of the generator represented by $U$.
operation AdiabaticStateEnergyUnitary( statePrepUnitary: (Qubit[] => ()),
adiabaticUnitary: (Qubit[] => ()),
qpeUnitary: (Qubit[] => () : Adjoint, Controlled),
phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double),
qubits: Qubit[]) : Double {
body {
statePrepUnitary(qubits);
adiabaticUnitary(qubits);
let phaseEst = phaseEstAlgorithm(OracleToDiscrete(qpeUnitary), qubits);
return phaseEst;
}
operation AdiabaticStateEnergyUnitary (statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit : Adjoint, Controlled), phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double), qubits : Qubit[]) : Double
{
statePrepUnitary(qubits);
adiabaticUnitary(qubits);
let phaseEst = phaseEstAlgorithm(OracleToDiscrete(qpeUnitary), qubits);
return phaseEst;
}
/// # Summary
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on an automatically allocated input state
/// $\ket{0...0}$, followed by adiabatic state preparation using a
/// `adiabaticUnitary`, and finally phase estimation with respect to
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on an automatically allocated input state
/// $\ket{0...0}$, followed by adiabatic state preparation using a
/// `adiabaticUnitary`, and finally phase estimation with respect to
/// `qpeUnitary`on the resulting state using a `phaseEstAlgorithm`.
///
/// # Input
@ -111,26 +106,24 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// An estimate $\hat{\phi}$ of the ground state energy $\phi$
/// of the generator represented by $U$.
operation AdiabaticStateEnergyEstimate( nQubits : Int,
statePrepUnitary: (Qubit[] => ()),
adiabaticUnitary: (Qubit[] => ()),
qpeUnitary: (Qubit[] => () : Adjoint, Controlled),
phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double)) : Double {
body {
mutable phaseEst = ToDouble(0);
using (qubits = Qubit[nQubits]) {
set phaseEst = AdiabaticStateEnergyUnitary( statePrepUnitary, adiabaticUnitary, qpeUnitary, phaseEstAlgorithm, qubits);
ResetAll(qubits);
}
return phaseEst;
operation AdiabaticStateEnergyEstimate (nQubits : Int, statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit : Adjoint, Controlled), phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double)) : Double
{
mutable phaseEst = ToDouble(0);
using (qubits = Qubit[nQubits])
{
set phaseEst = AdiabaticStateEnergyUnitary(statePrepUnitary, adiabaticUnitary, qpeUnitary, phaseEstAlgorithm, qubits);
ResetAll(qubits);
}
return phaseEst;
}
/// # Summary
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on an automatically allocated input state
/// phase estimation with respect to `qpeUnitary`on the resulting state
/// Convenience function that performs state preparation by applying a
/// `statePrepUnitary` on an automatically allocated input state
/// phase estimation with respect to `qpeUnitary`on the resulting state
/// using a `phaseEstAlgorithm`.
///
/// # Input
@ -151,15 +144,12 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// An estimate $\hat{\phi}$ of the ground state energy $\phi$
/// of the ground state energy of the generator represented by $U$.
operation EstimateEnergy(nQubits : Int,
statePrepUnitary: (Qubit[] => () ),
qpeUnitary: (Qubit[] => () : Adjoint, Controlled),
phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double) ) : Double {
body {
let phaseEst = AdiabaticStateEnergyEstimate( nQubits, statePrepUnitary, NoOp, qpeUnitary, phaseEstAlgorithm);
return phaseEst;
}
operation EstimateEnergy (nQubits : Int, statePrepUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit : Adjoint, Controlled), phaseEstAlgorithm : ((DiscreteOracle, Qubit[]) => Double)) : Double
{
let phaseEst = AdiabaticStateEnergyEstimate(nQubits, statePrepUnitary, NoOp<Qubit[]>, qpeUnitary, phaseEstAlgorithm);
return phaseEst;
}
}

Просмотреть файл

@ -1,15 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
// For an overview of the simulation library, see [Hamiltonian
namespace Microsoft.Quantum.Canon
{
// For an overview of the simulation library, see [Hamiltonian
// Simulation](applications#hamiltonian-simulation)
/// # Summary
/// A time-independent simulation technique converts an
// <xref:microsoft.quantum.canon.evolutiongenerator>
/// <xref:microsoft.quantum.canon.evolutiongenerator>
/// to unitary time evolution for some time-interval.
///
/// # Input
@ -22,8 +23,8 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// Unitary evolution by generator for time `Double`.
newtype SimulationAlgorithm = ((Double, EvolutionGenerator, Qubit[]) => () : Adjoint, Controlled);
newtype SimulationAlgorithm = ((Double, EvolutionGenerator, Qubit[]) => Unit : Adjoint, Controlled);
/// # Summary
/// A time-dependent simulation technique converts an
/// <xref:microsoft.quantum.canon.evolutionschedule>
@ -39,6 +40,8 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// Unitary evolution by time-dependent generator for time `Double`.
newtype TimeDependentSimulationAlgorithm = ((Double, EvolutionSchedule, Qubit[]) => () : Adjoint, Controlled);
newtype TimeDependentSimulationAlgorithm = ((Double, EvolutionSchedule, Qubit[]) => Unit : Adjoint, Controlled);
}

Просмотреть файл

@ -0,0 +1,253 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
/// # Summary
/// Given a list of $N$ coefficients $\alpha_j$, this returns a unitary $U$ that uses the Quantum-ROM
/// technique to prepare
/// an approximation $\tilde\rho\sum^{N-1}_{j=0}p_j\ket{j}\bra{j}$ of the purification of the density matrix
/// $\rho=\sum^{N-1}_{j=0}\frac{|alpha_j|}{\sum_k |\alpha_k|}\ket{j}\bra{j}$. In this approximation, the
/// error $\epsilon$ is such that $|p_j-\frac{|alpha_j|}{\sum_k |\alpha_k|}|\le \epsilon / N$ and
/// $\|\tilde\rho - \rho\|_1\| \le \epsilon$. In other words,
/// $$
/// \begin{align}
/// U\ket{0}^{\lceil\log_2 N\rceil}\ket{0}^{m}=\sum_{j=0}^{N-1}\sqrt{p_j} \ket{j}\ket{\text{garbage}_j}.
/// \end{align}
/// $$.
///
/// # Input
/// ## targetError
/// The target error $\epsilon$.
/// ## coefficients
/// Array of $N$ coefficients specifying the probability of basis states.
/// Negative numbers $-\alpha_j$ will be treated as positive $|\alpha_j|$.
///
/// # Output
/// ## First parameter
/// A tuple `(x,(y,z))` where `x = y + z` is the total number of qubits allocated,
/// `y` is the number of qubits for the `BigEndian` register, and `z` is the Number
/// of garbage qubits.
/// ## Second parameter
/// The one-norm $\sum_j |\alpha_j|$ of the coefficient array.
/// ## Third parameter
/// The unitary $U$.
///
/// # Example
/// The following code snippet prepares an purification of the $3$-qubit state
/// $\rho=\sum^{4}_{j=0}\frac{|alpha_j|}{\sum_k |\alpha_k|}\ket{j}\bra{j}$, where
/// $\vec\alpha=(1.0,2.0,3.0,4.0,5.0)$, and the error is `1e-3`;
/// ``` Q#
/// let coefficients = [1.0;2.0;3.0;4.0;5.0];
/// let targetError = 1e-3;
/// let ((nTotalQubits, (nIndexQubits, nGarbageQubits)), oneNorm, op) = QuantumROM(targetError, coefficients);
/// using(indexRegister = Qubit[nIndexQubits]) {
/// using(garbageRegister = Qubit[nGarbageQubits]) {
/// op(BigEndian(indexRegister), garbageRegister);
/// }
/// }
/// ```
///
/// # References
/// - Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity
/// Ryan Babbush, Craig Gidney, Dominic W. Berry, Nathan Wiebe, Jarrod McClean, Alexandru Paler, Austin Fowler, Hartmut Neven
/// https://arxiv.org/abs/1805.03662
function QuantumROM(targetError: Double, coefficients: Double[]) : ((Int, (Int, Int)), Double, ((BigEndian, Qubit[]) => Unit : Adjoint, Controlled)) {
let nBitsPrecision = -Ceiling(Lg(0.5*targetError))+1;
let (oneNorm, keepCoeff, altIndex) = QuantumROMDiscretization_(nBitsPrecision, coefficients);
let nCoeffs = Length(coefficients);
let nBitsIndices = Ceiling(Lg(ToDouble(nCoeffs)));
let op = QuantumROMImpl_(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, _, _);
let qubitCounts = QuantumROMQubitCount(targetError, nCoeffs);
return (qubitCounts, oneNorm, op);
}
/// # Summary
/// Returns count of number of qubits that must be allocated
/// to the operation returned by `QuantumROM`.
///
/// # Input
/// ## targetError
/// The target error $\epsilon$.
/// ## nCoeffs
/// Number of coefficients specified in `QuantumROM`.
///
/// # Output
/// ## First parameter
/// A tuple `(x,(y,z))` where `x = y + z` is the total number of qubits allocated,
/// `y` is the number of qubits for the `BigEndian` register, and `z` is the Number
/// of garbage qubits.
function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) : (Int, (Int, Int))
{
let nBitsPrecision = -Ceiling(Lg(0.5*targetError))+1;
let nBitsIndices = Ceiling(Lg(ToDouble(nCoeffs)));
let nGarbageQubits = nBitsIndices + 2 * nBitsPrecision + 1;
let nTotal = nGarbageQubits + nBitsIndices;
return (nTotal, (nBitsIndices, nGarbageQubits));
}
// Implementation step of `QuantumROM`. This splits a single
// qubit array into the subarrays required by the operation.
function QuantumROMQubitManager_(targetError: Double, nCoeffs: Int, qubits: Qubit[]) : ((BigEndian, Qubit[]), Qubit[]) {
let (nTotal, (nIndexRegister, nGarbageQubits)) = QuantumROMQubitCount(targetError, nCoeffs);
let registers = SplitArray([nIndexRegister, nGarbageQubits], qubits);
return((BigEndian(registers[0]), registers[1]), registers[2]);
}
// Classical processing
// This discretizes the coefficients such that
// |coefficient[i] * oneNorm - discretizedCoefficient[i] * discreizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}.
function QuantumROMDiscretization_(bitsPrecision: Int, coefficients: Double[]) : (Double, Int[], Int[]) {
let oneNorm = PNorm(1.0, coefficients);
let nCoefficients = Length(coefficients);
if(bitsPrecision > 31){
fail $"Bits of precision {bitsPrecision} unsurpported. Max is 31.";
}
if(nCoefficients <= 1){
fail $"Cannot prepare state with less than 2 coefficients.";
}
if(oneNorm == 0.0){
fail $"State must have at least one coefficient > 0";
}
let barHeight = 2^bitsPrecision - 1;
mutable altIndex = IntArrayFromRange(0..nCoefficients-1);
mutable keepCoeff = Map(QuantumROMDiscretizationRoundCoefficients_(_, oneNorm, nCoefficients, barHeight), coefficients);
// Calculate difference between number of discretized bars vs. maximum
mutable bars = 0;
for(idxCoeff in 0..nCoefficients-1){
set bars = bars + keepCoeff[idxCoeff] - barHeight;
}
//Message($"Excess bars {bars}.");
// Uniformly distribute excess bars acress coefficients.
for(idx in 0..AbsI(bars)-1){
if(bars > 0){
set keepCoeff[idx] = keepCoeff[idx]-1;
}
else{
set keepCoeff[idx] = keepCoeff[idx]+1;
}
}
mutable barSink = new Int[nCoefficients];
mutable barSource = new Int[nCoefficients];
mutable nBarSink = 0;
mutable nBarSource = 0;
for(idxCoeff in 0..nCoefficients-1) {
if(keepCoeff[idxCoeff] > barHeight){
set barSource[nBarSource] = idxCoeff;
set nBarSource = nBarSource + 1;
}
elif(keepCoeff[idxCoeff] < barHeight){
set barSink[nBarSink] = idxCoeff;
set nBarSink = nBarSink + 1;
}
}
for(rep in 0..nCoefficients * 10){
if(nBarSource > 0 && nBarSink > 0){
let idxSink = barSink[nBarSink-1];
let idxSource = barSource[nBarSource-1];
set nBarSink = nBarSink - 1;
set nBarSource = nBarSource - 1;
set keepCoeff[idxSource] = keepCoeff[idxSource] - barHeight + keepCoeff[idxSink];
set altIndex[idxSink] = idxSource;
if (keepCoeff[idxSource] < barHeight)
{
set barSink[nBarSink] = idxSource;
set nBarSink = nBarSink + 1;
}
elif(keepCoeff[idxSource] > barHeight)
{
set barSource[nBarSource] = idxSource;
set nBarSource = nBarSource + 1;
}
}
elif(nBarSource > 0){
//Message($"rep: {rep}, nBarSource {nBarSource}.");
let idxSource = barSource[nBarSource-1];
set nBarSource = nBarSource - 1;
set keepCoeff[idxSource] = barHeight;
}
else {
return (oneNorm, keepCoeff, altIndex);
}
}
return (oneNorm, keepCoeff, altIndex);
}
// Used in QuantumROM implementation.
function QuantumROMDiscretizationRoundCoefficients_(coefficient: Double, oneNorm: Double, nCoefficients: Int, barHeight: Int) : Int {
return Round((AbsD(coefficient) / oneNorm) * ToDouble(nCoefficients) * ToDouble(barHeight));
}
// Used in QuantumROM implementation.
operation QuantumROMImpl_(nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, keepCoeff: Int[], altIndex: Int[], indexRegister: BigEndian, garbageRegister: Qubit[]) : Unit {
body (...) {
let unitaryGenerator = (nCoeffs, QuantumROMWriteBitStringUnitary_(_, keepCoeff, altIndex));
let garbageIdx0 = nBitsIndices;
let garbageIdx1 = garbageIdx0 + nBitsPrecision;
let garbageIdx2 = garbageIdx1 + nBitsPrecision;
let garbageIdx3 = garbageIdx2 + 1;
let altIndexRegister = BigEndian(garbageRegister[0..garbageIdx0-1]);
let keepCoeffRegister = BigEndian(garbageRegister[garbageIdx0..garbageIdx1 - 1]);
let uniformKeepCoeffRegister = BigEndian(garbageRegister[garbageIdx1..garbageIdx2 - 1]);
let flagQubit = garbageRegister[garbageIdx3 - 1];
// Create uniform superposition over index and alt coeff register.
PrepareUniformSuperposition(nCoeffs, indexRegister);
ApplyToEachCA(H, uniformKeepCoeffRegister!);
// Write bitstrings to altIndex and keepCoeff register.
MultiplexOperationsFromGenerator(unitaryGenerator, indexRegister, (keepCoeffRegister, altIndexRegister));
// Perform comparison
ApplyRippleCarryComparatorBE(uniformKeepCoeffRegister, keepCoeffRegister, flagQubit);
let indexRegisterSize = Length(indexRegister!);
// Swap in register based on comparison
for(idx in 0..nBitsIndices-1){
(Controlled SWAP)([flagQubit], (indexRegister![Length(indexRegister!) - nBitsIndices + idx], altIndexRegister![idx]));
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
// Used in QuantumROM implementation.
function QuantumROMWriteBitStringUnitary_(idx: Int, keepCoeff: Int[], altIndex: Int[]) : ((BigEndian, BigEndian) => Unit : Adjoint, Controlled) {
return QuantumROMWriteBitString_(idx, keepCoeff, altIndex, _, _);
}
// Used in QuantumROM implementation.
operation QuantumROMWriteBitString_(idx: Int, keepCoeff: Int[], altIndex: Int[], keepCoeffRegister: BigEndian, altIndexRegister: BigEndian) : Unit {
body (...) {
InPlaceXorBE(keepCoeff[idx], keepCoeffRegister);
InPlaceXorBE(altIndex[idx], altIndexRegister);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
}

Просмотреть файл

@ -1,18 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
// This library returns operations that prepare a specified quantum state
// from the computational basis state $\ket{0...0}$.
/// # Summary
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with positive coefficients $\alpha_j\ge 0$ from
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with positive coefficients $\alpha_j\ge 0$ from
/// the $n$-qubit computational basis state $\ket{0...0}$.
///
/// The action of U on a newly-allocated register is given by
@ -22,42 +24,45 @@ namespace Microsoft.Quantum.Canon
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ coefficients $\alpha_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ coefficients $\alpha_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// # Output
/// A state-preparation unitary operation $U$.
///
/// # Remarks
/// Negative input coefficients $\alpha_j < 0$ will be treated as though
/// positive with value $|\alpha_j|$. `coefficients` will be padded with
/// positive with value $|\alpha_j|$. `coefficients` will be padded with
/// elements $\alpha_j = 0.0$ if fewer than $2^n$ are specified.
///
/// # Example
/// The following snippet prepares the quantum state $\ket{\psi}=\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{2}$
/// in the qubit register `qubitsBE`.
/// ```qsharp
/// mutable amplitudes = [Sqrt(0.125); 0.0; Sqrt(0.875); 0.0];
/// mutable amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0];
/// let op = StatePreparationPositiveCoefficients(amplitudes);
/// using(qubits = Qubit[2]){
/// let qubitsBE = BigEndian(qubits);
/// op(qubitsBE);
/// }
/// ```
function StatePreparationPositiveCoefficients(coefficients: Double[]) : (BigEndian => (): Adjoint, Controlled)
function StatePreparationPositiveCoefficients (coefficients : Double[]) : (BigEndian => Unit : Adjoint, Controlled)
{
let nCoefficients = Length(coefficients);
mutable coefficientsComplexPolar = new ComplexPolar[nCoefficients];
for(idx in 0..nCoefficients - 1){
for (idx in 0 .. nCoefficients - 1)
{
set coefficientsComplexPolar[idx] = ComplexPolar(AbsD(coefficients[idx]), 0.0);
}
return PrepareArbitraryState(coefficientsComplexPolar, _);
}
/// # Summary
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from
/// the $n$-qubit computational basis state $\ket{0...0}$.
///
/// The action of U on a newly-allocated register is given by
@ -67,25 +72,25 @@ namespace Microsoft.Quantum.Canon
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ complex coefficients represented by their
/// absolute value and phase $(r_j, t_j)$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ complex coefficients represented by their
/// absolute value and phase $(r_j, t_j)$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// # Output
/// A state-preparation unitary operation $U$.
///
/// # Remarks
/// Negative input coefficients $r_j < 0$ will be treated as though
/// positive with value $|r_j|$. `coefficients` will be padded with
/// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are
/// positive with value $|r_j|$. `coefficients` will be padded with
/// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are
/// specified.
///
/// # Example
/// The following snippet prepares the quantum state $\ket{\psi}=e^{i 0.1}\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{2}$
/// in the qubit register `qubitsBE`.
/// ```qsharp
/// mutable amplitudes = [Sqrt(0.125); 0.0; Sqrt(0.875); 0.0];
/// mutable phases = [0.1; 0.0; 0.0; 0.0];
/// mutable amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0];
/// mutable phases = [0.1, 0.0, 0.0, 0.0];
/// mutable complexNumbers = new ComplexPolar[4];
/// for(idx in 0..3){
/// set complexNumbers[idx] = ComplexPolar(amplitudes, phases);
@ -96,103 +101,107 @@ namespace Microsoft.Quantum.Canon
/// op(qubitsBE);
/// }
/// ```
function StatePreparationComplexCoefficients (coefficients: ComplexPolar[]) : (BigEndian => (): Adjoint, Controlled)
function StatePreparationComplexCoefficients (coefficients : ComplexPolar[]) : (BigEndian => Unit : Adjoint, Controlled)
{
return PrepareArbitraryState(coefficients, _);
}
/// # Summary
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from
/// Returns a unitary operation $U$ that prepares an arbitrary quantum
/// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from
/// the $n$-qubit computational basis state $\ket{0...0}$.
///
/// $U\ket{0...0}=\ket{\psi}=\frac{\sum^{2^n-1}_{j=0}r_j e^{i t_j}\ket{j}}{\sqrt{\sum^{2^n-1}_{j=0}|r_j|^2}}$.
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ complex coefficients represented by their
/// absolute value and phase $(r_j, t_j)$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ complex coefficients represented by their
/// absolute value and phase $(r_j, t_j)$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// ## qubits
/// Qubit register encoding number states in big-endian format. This is
/// expected to be initialized in the computational basis state
/// expected to be initialized in the computational basis state
/// $ket{0...0}$.
///
/// # Remarks
/// Negative input coefficients $r_j < 0$ will be treated as though
/// positive with value $|r_j|$. `coefficients` will be padded with
/// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are
/// positive with value $|r_j|$. `coefficients` will be padded with
/// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are
/// specified.
///
/// # References
/// - Synthesis of Quantum Logic Circuits
/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov
/// https://arxiv.org/abs/quant-ph/0406176
operation PrepareArbitraryState(coefficients: ComplexPolar[], qubits: BigEndian) : ()
operation PrepareArbitraryState (coefficients : ComplexPolar[], qubits : BigEndian) : Unit
{
body
body (...)
{
// pad coefficients at tail length to a power of 2.
let coefficientsPadded = Pad(-2^(Length(qubits)), ComplexPolar(0.0, 0.0), coefficients);
let target = qubits[Length(qubits)-1];
let coefficientsPadded = Pad(-2 ^ Length(qubits!), ComplexPolar(0.0, 0.0), coefficients);
let target = (qubits!)[Length(qubits!) - 1];
let op = (Adjoint PrepareArbitraryState_(coefficientsPadded, _, _))(_, target);
if(Length(qubits) > 1){
let control = BigEndian(qubits[0..Length(qubits)-2]);
if (Length(qubits!) > 1)
{
let control = BigEndian((qubits!)[0 .. Length(qubits!) - 2]);
op(control);
}
else{
else
{
let control = BigEndian(new Qubit[0]);
op(control);
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implementation step of arbitrary state preparation procedure.
///
/// # See Also
/// - Microsoft.Quantum.Canon.PrepareArbitraryState
/// - Microsoft.Quantum.Canon.MultiplexPauli
operation PrepareArbitraryState_ (coefficients: ComplexPolar[], control: BigEndian, target: Qubit) : ()
operation PrepareArbitraryState_ (coefficients : ComplexPolar[], control : BigEndian, target : Qubit) : Unit
{
body
body (...)
{
// For each 2D block, compute disentangling single-qubit rotation parameters
let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients_(coefficients);
MultiplexPauli(disentanglingZ, PauliZ, control, target);
MultiplexPauli(disentanglingY, PauliY, control, target);
// target is now in |0> state up to the phase given by arg of newCoefficients.
// Continue recursion while there are control qubits.
if(Length(control) == 0){
let (abs, arg) = newCoefficients[0];
if (Length(control!) == 0)
{
let (abs, arg) = newCoefficients[0]!;
Exp([PauliI], -1.0 * arg, [target]);
}
else{
let newControl = BigEndian(control[0..Length(control)-2]);
let newTarget = control[Length(control)-1];
else
{
let newControl = BigEndian((control!)[0 .. Length(control!) - 2]);
let newTarget = (control!)[Length(control!) - 1];
PrepareArbitraryState_(newCoefficients, newControl, newTarget);
}
}
adjoint auto
controlled auto
adjoint controlled auto
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Given two complex numbers $a0, a1$, computes coordinates
/// on the Bloch sphere such that
/// on the Bloch sphere such that
/// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$.
///
/// # Input
@ -203,35 +212,41 @@ namespace Microsoft.Quantum.Canon
///
/// # Output
/// A tuple containing `(ComplexPolar(r, t), phi, theta)`.
function BlochSphereCoordinates(a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) {
function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double)
{
let abs0 = AbsComplexPolar(a0);
let abs1 = AbsComplexPolar(a1);
let arg0 = ArgComplexPolar(a0);
let arg1 = ArgComplexPolar(a1);
let r = Sqrt(abs0 * abs0 + abs1 * abs1);
let t = 0.5 * (arg0 + arg1);
let phi = arg1 - arg0;
let theta = 2.0 * ArcTan2(abs1, abs0);
return (ComplexPolar(r, t), phi, theta);
}
/// # Summary
/// Implementation step of arbitrary state preparation procedure.
/// # See Also
/// - Microsoft.Quantum.Canon.PrepareArbitraryState
function StatePreparationSBMComputeCoefficients_(coefficients: ComplexPolar[]) : (Double[], Double[], ComplexPolar[]) {
mutable disentanglingZ = new Double[Length(coefficients)/2];
mutable disentanglingY = new Double[Length(coefficients)/2];
mutable newCoefficients = new ComplexPolar[Length(coefficients)/2];
for(idxCoeff in 0..2..Length(coefficients) - 1){
let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff+1]);
set disentanglingZ[idxCoeff/2] = 0.5 * phi;
set disentanglingY[idxCoeff/2] = 0.5 * theta;
set newCoefficients[idxCoeff/2] = rt;
function StatePreparationSBMComputeCoefficients_ (coefficients : ComplexPolar[]) : (Double[], Double[], ComplexPolar[])
{
mutable disentanglingZ = new Double[Length(coefficients) / 2];
mutable disentanglingY = new Double[Length(coefficients) / 2];
mutable newCoefficients = new ComplexPolar[Length(coefficients) / 2];
for (idxCoeff in 0 .. 2 .. Length(coefficients) - 1)
{
let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]);
set disentanglingZ[idxCoeff / 2] = 0.5 * phi;
set disentanglingY[idxCoeff / 2] = 0.5 * theta;
set newCoefficients[idxCoeff / 2] = rt;
}
return (disentanglingY, disentanglingZ, newCoefficients);
}
}

Просмотреть файл

@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
/// # Summary
/// This unitary $U$ creates a uniform superposition over all number states
/// $0$ to $M-1$, given an input state $\ket{0\cdots 0}$. In other words,
/// $$
/// \begin{align}
/// U\ket{0}=\frac{1}{\sqrt{M}}\sum_{j=1}^{M-1}\ket{j}.
/// \end{align}
/// $$.
///
/// # Input
/// ## nIndices
/// The desired number of states $M$ in the uniform superposition.
/// ## indexRegister
/// The qubit register that stores the number states in `BigEndian` format.
/// This register must be able to store the number $M-1$, and is assumed to be
/// initialized in the state $\ket{0\cdots 0}$.
///
/// # Example
/// The following example prepares the state $\frac{1}{\sqrt{6}}\sum_{j=1}^{5}\ket{j}$
/// on $3$ qubits.
/// ``` Q#
/// let nIndices = 6;
/// using(indexRegister = Qubit[3]) {
/// PrepareUniformSuperposition(nIndices, BigEndian(indexRegister));
/// }
/// ```
operation PrepareUniformSuperposition(nIndices: Int, indexRegister: BigEndian) : Unit {
body (...) {
if(nIndices == 0) {
fail $"Cannot prepare uniform superposition over {nIndices} state.";
}
elif(nIndices == 1) {
// Superposition over one state, so do nothing.
}
elif(nIndices == 2){
H(indexRegister![Length(indexRegister!) - 1]);
}
else{
let nQubits = Ceiling(Lg(ToDouble(nIndices)));
if (nQubits > Length(indexRegister!)){
fail $"Cannot prepare uniform superposition over {nIndices} states as it is larger than the qubit register.";
}
using(flagQubit = Qubit[3]){
let targetQubits = indexRegister![Length(indexRegister!) - nQubits..Length(indexRegister!) - 1];
let qubits = flagQubit + targetQubits;
let stateOracle = StateOracle(PrepareUniformSuperposition_(nIndices, nQubits, _, _));
(AmpAmpByOracle(1, stateOracle, 0))(qubits);
ApplyToEachCA(X, flagQubit);
}
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
/// # Summary
/// Implementation step of <xref:microsoft.quantum.canon.prepareuniformsuperposition>
operation PrepareUniformSuperposition_(nIndices: Int, nQubits: Int, idxFlag: Int, qubits: Qubit[]) : Unit {
body (...) {
let targetQubits = qubits[3..3 + nQubits-1];
let flagQubit = qubits[0];
let auxillaryQubits = qubits[1..2];
let theta = ArcSin(Sqrt(ToDouble(2^nQubits)/ToDouble(nIndices))*Sin(PI() / 6.0));
//let theta = PI() * 0.5;
ApplyToEachCA(H, targetQubits);
using(compareQubits = Qubit[nQubits]){
InPlaceXorBE(nIndices - 1, BigEndian(compareQubits));
ApplyRippleCarryComparatorBE(BigEndian(targetQubits), BigEndian(compareQubits), auxillaryQubits[0]);
X(auxillaryQubits[0]);
InPlaceXorBE(nIndices - 1, BigEndian(compareQubits));
}
Exp([PauliY], -theta, [auxillaryQubits[1]]);
(Controlled X)(auxillaryQubits, flagQubit);
}
adjoint auto;
controlled auto;
adjoint controlled auto;
}
}

Просмотреть файл

@ -0,0 +1,390 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
///////////////////////////////////////////////////////////////////////////////////////////
// Types and supporting functions for representing unsigned integers in arrays of qubits //
///////////////////////////////////////////////////////////////////////////////////////////
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Register that encodes an unsigned integer in little-endian order. The
/// qubit with index `0` encodes the lowest bit of an unsigned integer
///
/// # Remarks
/// We abbreviate `LittleEndian` as `LE` in the documentation.
newtype LittleEndian = Qubit[];
/// # Summary
/// Register that encodes an unsigned integer in big-endian order. The
/// qubit with index `0` encodes the highest bit of an unsigned integer
///
/// # Remarks
/// We abbreviate `BigEndian` as `BE` in the documentation.
newtype BigEndian = Qubit[];
/// # Summary
/// Little-endian unsigned integers in QFT basis.
/// For example, if |x⟩ is little-endian encoding of integer x in computational basis,
/// then QFTLE|x⟩ is encoding of x in QFT basis.
///
/// # Remarks
/// We abbreviate `LittleEndian` as `LE` in the documentation.
///
/// # See Also
/// - microsoft.quantum.canon.qft
/// - microsoft.quantum.canon.qftle
newtype PhaseLittleEndian = Qubit[];
/// # Summary
/// Applies an operation that takes little-endian input to a register encoding
/// an unsigned integer using big-endian format.
///
/// # Input
/// ## op
/// Operation that acts on a little-endian register.
/// ## register
/// A big-endian register to be transformed.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyReversedOpLittlEndianA
/// - Microsoft.Quantum.Canon.ApplyReversedOpLittlEndianC
/// - Microsoft.Quantum.Canon.ApplyReversedOpLittlEndianCA
operation ApplyReversedOpLittleEndian (op : (LittleEndian => Unit), register : BigEndian) : Unit
{
let bareReversed = Reverse(register!);
let reversed = LittleEndian(bareReversed);
op(reversed);
}
/// # Summary
/// Applies an operation that takes little-endian input and that supports
/// the adjoint functor to a register encoding
/// an unsigned integer using big-endian format.
///
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedoplittleendian"
operation ApplyReversedOpLittleEndianA (op : (LittleEndian => Unit : Adjoint), register : BigEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = LittleEndian(bareReversed);
op(reversed);
}
adjoint invert;
}
/// # Summary
/// Applies an operation that takes little-endian input and that supports
/// the controlled functor to a register encoding
/// an unsigned integer using big-endian format.
///
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedoplittleendian"
operation ApplyReversedOpLittleEndianC (op : (LittleEndian => Unit : Controlled), register : BigEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = LittleEndian(bareReversed);
op(reversed);
}
controlled distribute;
}
/// # Summary
/// Applies an operation that takes little-endian input and that supports
/// the controlled and adjoint functors to a register encoding
/// an unsigned integer using big-endian format.
///
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedoplittleendian"
operation ApplyReversedOpLittleEndianCA (op : (LittleEndian => Unit : Controlled, Adjoint), register : BigEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = LittleEndian(bareReversed);
op(reversed);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Applies an operation that takes big-endian input to a register encoding
/// an unsigned integer using little-endian format.
///
/// # Input
/// ## op
/// Operation that acts on big-endian register
/// ## register
/// little-endian register to be transformed
///
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedopbigendiana"
/// - @"microsoft.quantum.canon.applyreversedopbigendianc"
/// - @"microsoft.quantum.canon.applyreversedopbigendianca"
operation ApplyReversedOpBigEndian (op : (BigEndian => Unit), register : LittleEndian) : Unit
{
let bareReversed = Reverse(register!);
let reversed = BigEndian(bareReversed);
op(reversed);
}
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedopbigendian"
operation ApplyReversedOpBigEndianA (op : (BigEndian => Unit : Adjoint), register : LittleEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = BigEndian(bareReversed);
op(reversed);
}
adjoint invert;
}
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedopbigendian"
operation ApplyReversedOpBigEndianC (op : (BigEndian => Unit : Controlled), register : LittleEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = BigEndian(bareReversed);
op(reversed);
}
controlled distribute;
}
/// # See Also
/// - @"microsoft.quantum.canon.applyreversedopbigendian"
operation ApplyReversedOpBigEndianCA (op : (BigEndian => Unit : Controlled, Adjoint), register : LittleEndian) : Unit
{
body (...)
{
let bareReversed = Reverse(register!);
let reversed = BigEndian(bareReversed);
op(reversed);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Uses SWAP gates to reverse the order of the qubits in
/// a register.
///
/// # Input
/// ## register
/// The qubits order of which should be reversed using SWAP gates
operation SwapReverseRegister (register : Qubit[]) : Unit
{
body (...)
{
let totalQubits = Length(register);
let halfTotal = totalQubits / 2;
for (i in 0 .. halfTotal - 1)
{
SWAP(register[i], register[(totalQubits - i) - 1]);
}
}
adjoint self;
controlled distribute;
controlled adjoint self;
}
/// # Summary
/// Applies an operation that takes a
/// <xref:microsoft.quantum.canon.littleendian> register as input
/// on a target register of type <xref:microsoft.quantum.canon.phaselittleendian>.
///
/// # Input
/// ## op
/// The operation to be applied.
/// ## target
/// The register to which the operation is applied.
///
/// # Remarks
/// The register is transformed to `PhaseLittleEndian` by the use of
/// <xref:microsoft.quantum.canon.qftle> and is then returned to
/// its original representation after application of `op`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyPhaseLEOperationonLEA
/// - Microsoft.Quantum.Canon.ApplyPhaseLEOperationonLEA
/// - Microsoft.Quantum.Canon.ApplyPhaseLEOperationonLECA
operation ApplyPhaseLEOperationOnLE (op : (PhaseLittleEndian => Unit), target : LittleEndian) : Unit
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
op(phaseLE);
Adjoint QFTLE(target);
}
/// # See Also
/// - @"microsoft.quantum.canon.applyphaseleoperationonle"
operation ApplyPhaseLEOperationOnLEA (op : (PhaseLittleEndian => Unit : Adjoint), target : LittleEndian) : Unit
{
body (...)
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
op(phaseLE);
Adjoint QFTLE(target);
}
adjoint invert;
}
/// # See Also
/// - @"microsoft.quantum.canon.applyphaseleoperationonle"
operation ApplyPhaseLEOperationOnLEC (op : (PhaseLittleEndian => Unit : Controlled), target : LittleEndian) : Unit
{
body (...)
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
op(phaseLE);
Adjoint QFTLE(target);
}
controlled (controls, ...)
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
Controlled op(controls, phaseLE);
Adjoint QFTLE(target);
}
}
/// # See Also
/// - @"microsoft.quantum.canon.applyphaseleoperationonle"
operation ApplyPhaseLEOperationOnLECA (op : (PhaseLittleEndian => Unit : Controlled, Adjoint), target : LittleEndian) : Unit
{
body (...)
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
op(phaseLE);
Adjoint QFTLE(target);
}
adjoint invert;
controlled (controls, ...)
{
QFTLE(target);
let phaseLE = PhaseLittleEndian(target!);
Controlled op(controls, phaseLE);
Adjoint QFTLE(target);
}
controlled adjoint invert;
}
/// # Summary
/// Applies an operation that takes a
/// <xref:microsoft.quantum.canon.phaselittleendian> register as input
/// on a target register of type <xref:microsoft.quantum.canon.littleendian>.
///
/// # Input
/// ## op
/// The operation to be applied.
/// ## target
/// The register to which the operation is applied.
///
/// # Remarks
/// The register is transformed to `LittleEndian` by the use of
/// <xref:microsoft.quantum.canon.qftle> and is then returned to
/// its original representation after application of `op`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLEA
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLEA
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLECA
operation ApplyLEOperationOnPhaseLE (op : (LittleEndian => Unit), target : PhaseLittleEndian) : Unit
{
let targetLE = LittleEndian(target!);
With(Adjoint QFTLE, op, targetLE);
}
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLE
operation ApplyLEOperationOnPhaseLEA (op : (LittleEndian => Unit : Adjoint), target : PhaseLittleEndian) : Unit
{
body (...)
{
let targetLE = LittleEndian(target!);
WithA(Adjoint QFTLE, op, targetLE);
}
adjoint invert;
}
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLE
operation ApplyLEOperationOnPhaseLEC (op : (LittleEndian => Unit : Controlled), target : PhaseLittleEndian) : Unit
{
body (...)
{
let targetLE = LittleEndian(target!);
WithC(Adjoint QFTLE, op, targetLE);
}
controlled distribute;
}
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyLEOperationonPhaseLE
operation ApplyLEOperationOnPhaseLECA (op : (LittleEndian => Unit : Controlled, Adjoint), target : PhaseLittleEndian) : Unit
{
body (...)
{
let targetLE = LittleEndian(target!);
WithCA(Adjoint QFTLE, op, targetLE);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Applies a unitary operator on the target register if the control register state corresponds to a specified bit mask.
///
@ -18,20 +21,22 @@ namespace Microsoft.Quantum.Canon {
/// ## controlRegister
/// Quantum register that controls application of `oracle`.
///
/// # Remarks
/// # Remarks
/// The length of `bits` and `controlRegister` must be equal.
/// For example, `bits = [0;1;0;0;1]` means that `oracle` is applied if and only if `controlRegister`" is in the state $\ket{0}\ket{1}\ket{0}\ket{0}\ket{1}$.
operation ControlledOnBitStringImpl<'T>(bits : Bool[] , oracle: ('T => (): Adjoint, Controlled), controlRegister : Qubit[], targetRegister: 'T) : ()
/// For example, `bits = [0,1,0,0,1]` means that `oracle` is applied if and only if `controlRegister`" is in the state $\ket{0}\ket{1}\ket{0}\ket{0}\ket{1}$.
operation ControlledOnBitStringImpl<'T> (bits : Bool[], oracle : ('T => Unit : Adjoint, Controlled), controlRegister : Qubit[], targetRegister : 'T) : Unit
{
body{
WithCA(ApplyPauliFromBitString(PauliX, false, bits, _), (Controlled oracle)(_, targetRegister), controlRegister);
}
adjoint auto
controlled auto
adjoint controlled auto
body (...)
{
WithCA(ApplyPauliFromBitString(PauliX, false, bits, _), Controlled oracle(_, targetRegister), controlRegister);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Returns a unitary operator that applies an oracle on the target register if the control register state corresponds to a specified bit mask.
///
@ -43,11 +48,12 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A unitary operator that applies `oracle` on the target register if the control register state corresponds to the bit mask `bits`.
function ControlledOnBitString<'T>(bits : Bool[] , oracle: ('T => (): Adjoint, Controlled)) : ((Qubit[],'T) => (): Adjoint, Controlled)
function ControlledOnBitString<'T> (bits : Bool[], oracle : ('T => Unit : Adjoint, Controlled)) : ((Qubit[], 'T) => Unit : Adjoint, Controlled)
{
return ControlledOnBitStringImpl(bits, oracle, _, _);
return ControlledOnBitStringImpl(bits, oracle, _, _);
}
/// # Summary
/// Applies a unitary operator on the target register if the control register state corresponds to a specified positive integer.
///
@ -61,24 +67,23 @@ namespace Microsoft.Quantum.Canon {
/// ## controlRegister
/// Quantum register that controls application of `oracle`.
///
/// # Remarks
/// # Remarks
/// `numberState` must be at most $2^\texttt{Length(controlRegister)} - 1$.
/// For example, `numberState = 537` means that `oracle` is applied if and only if `controlRegister` is in the state $\ket{537}$.
operation ControlledOnIntImpl<'T>(numberState : Int , oracle: ('T => (): Adjoint, Controlled), controlRegister : Qubit[], targetRegister: 'T) : ()
operation ControlledOnIntImpl<'T> (numberState : Int, oracle : ('T => Unit : Adjoint, Controlled), controlRegister : Qubit[], targetRegister : 'T) : Unit
{
body {
let bits = BoolArrFromPositiveInt(numberState, Length(controlRegister));
(ControlledOnBitString(bits, oracle))(controlRegister, targetRegister);
}
adjoint auto
controlled auto
adjoint controlled auto
body (...)
{
let bits = BoolArrFromPositiveInt(numberState, Length(controlRegister));
(ControlledOnBitString(bits, oracle))(controlRegister, targetRegister);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Returns a unitary operator that applies an oracle on the target register if the control register state corresponds to a specified positive integer.
///
@ -90,9 +95,11 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// A unitary operator that applies `oracle` on the target register if the control register state corresponds to the number state `numberState`.
function ControlledOnInt<'T>(numberState : Int , oracle: ('T => (): Adjoint, Controlled)) : ((Qubit[],'T) => (): Adjoint, Controlled)
function ControlledOnInt<'T> (numberState : Int, oracle : ('T => Unit : Adjoint, Controlled)) : ((Qubit[], 'T) => Unit : Adjoint, Controlled)
{
return ControlledOnIntImpl(numberState, oracle, _, _);
return ControlledOnIntImpl(numberState, oracle, _, _);
}
}

Просмотреть файл

@ -1,23 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Applies multiply-controlled unitary operation $U$ that performs
/// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$
/// Applies multiply-controlled unitary operation $U$ that performs
/// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$
/// when controlled by the $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i P \theta_j}$.
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// ## pauli
/// Pauli operator $P$ that determines axis of rotation.
@ -30,45 +32,54 @@ namespace Microsoft.Quantum.Canon
/// Single qubit register that is rotated by $e^{i P \theta_j}$.
///
/// # Remarks
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// fewer than $2^n$ are specified.
operation MultiplexPauli(coefficients:Double[], pauli: Pauli, control: BigEndian, target: Qubit) : (){
body{
if(pauli == PauliZ){
operation MultiplexPauli (coefficients : Double[], pauli : Pauli, control : BigEndian, target : Qubit) : Unit
{
body (...)
{
if (pauli == PauliZ)
{
let op = MultiplexZ(coefficients, control, _);
op(target);
}
elif(pauli == PauliX){
elif (pauli == PauliX)
{
let op = MultiplexPauli(coefficients, PauliZ, control, _);
WithCA(H, op, target);
}
elif(pauli == PauliY){
elif (pauli == PauliY)
{
let op = MultiplexPauli(coefficients, PauliX, control, _);
WithCA(Adjoint S, op, target);
}
elif(pauli == PauliI){
elif (pauli == PauliI)
{
ApplyDiagonalUnitary(coefficients, control);
}
else{
else
{
fail $"MultiplexPauli failed. Invalid pauli {pauli}.";
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Applies multiply-controlled unitary operation $U$ that performs
/// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$
/// Applies multiply-controlled unitary operation $U$ that performs
/// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$
/// when controlled by the $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i Z \theta_j}$.
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// ## control
/// $n$-qubit control register that encodes number states $\ket{j}$ in
@ -78,120 +89,139 @@ namespace Microsoft.Quantum.Canon
/// Single qubit register that is rotated by $e^{i P \theta_j}$.
///
/// # Remarks
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// fewer than $2^n$ are specified.
///
/// # References
/// - Synthesis of Quantum Logic Circuits
/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov
/// https://arxiv.org/abs/quant-ph/0406176
operation MultiplexZ(coefficients: Double[], control: BigEndian, target: Qubit) : () {
body{
operation MultiplexZ (coefficients : Double[], control : BigEndian, target : Qubit) : Unit
{
body (...)
{
// pad coefficients length at tail to a power of 2.
let coefficientsPadded = Pad(-2^(Length(control)), 0.0, coefficients);
if(Length(coefficientsPadded) == 1){
let coefficientsPadded = Pad(-2 ^ Length(control!), 0.0, coefficients);
if (Length(coefficientsPadded) == 1)
{
// Termination case
Exp([PauliZ], coefficientsPadded[0], [target]);
}
else{
else
{
// Compute new coefficients.
let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded);
MultiplexZ(coefficients0, BigEndian(control[1..Length(control)-1]), target);
CNOT(control[0], target);
MultiplexZ(coefficients1, BigEndian(control[1..Length(control)-1]), target);
CNOT(control[0], target);
MultiplexZ(coefficients0, BigEndian((control!)[1 .. Length(control!) - 1]), target);
CNOT((control!)[0], target);
MultiplexZ(coefficients1, BigEndian((control!)[1 .. Length(control!) - 1]), target);
CNOT((control!)[0], target);
}
}
adjoint auto
controlled (controlRegister) {
adjoint invert;
controlled (controlRegister, ...)
{
// pad coefficients length to a power of 2.
let coefficientsPadded = Pad(2^(Length(control)+1), 0.0, Pad(-2^(Length(control)), 0.0, coefficients));
let coefficientsPadded = Pad(2 ^ (Length(control!) + 1), 0.0, Pad(-2 ^ Length(control!), 0.0, coefficients));
let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded);
MultiplexZ(coefficients0, control, target);
(Controlled X)(controlRegister, target);
Controlled X(controlRegister, target);
MultiplexZ(coefficients1, control, target);
(Controlled X)(controlRegister, target);
Controlled X(controlRegister, target);
}
adjoint controlled auto
controlled adjoint invert;
}
/// # Summary
/// Applies Diagonal unitary operation $U$ that applies a complex phase
/// Applies Diagonal unitary operation $U$ that applies a complex phase
/// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}e^{i\theta_j}\ket{j}\bra{j}$.
///
/// # Input
/// ## coefficients
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient
/// indexes the number state $\ket{j}$ encoded in big-endian format.
///
/// ## control
/// $n$-qubit control register that encodes number states $\ket{j}$ in
/// big-endian format.
///
/// # Remarks
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// `coefficients` will be padded with elements $\theta_j = 0.0$ if
/// fewer than $2^n$ are specified.
///
/// # References
/// - Synthesis of Quantum Logic Circuits
/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov
/// https://arxiv.org/abs/quant-ph/0406176
operation ApplyDiagonalUnitary(coefficients: Double[], qubits: BigEndian) : () {
body{
if(Length(qubits) == 0){
operation ApplyDiagonalUnitary (coefficients : Double[], qubits : BigEndian) : Unit
{
body (...)
{
if (Length(qubits!) == 0)
{
fail $"operation ApplyDiagonalUnitary -- Number of qubits must be greater than 0.";
}
// pad coefficients length at tail to a power of 2.
let coefficientsPadded = Pad(-2^(Length(qubits)), 0.0, coefficients);
let coefficientsPadded = Pad(-2 ^ Length(qubits!), 0.0, coefficients);
// Compute new coefficients.
let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded);
MultiplexZ(coefficients1, BigEndian(qubits[1..Length(qubits)-1]), qubits[0]);
if(Length(coefficientsPadded) == 2){
MultiplexZ(coefficients1, BigEndian((qubits!)[1 .. Length(qubits!) - 1]), (qubits!)[0]);
if (Length(coefficientsPadded) == 2)
{
// Termination case
Exp([PauliI], 1.0 * coefficients0[0], qubits);
Exp([PauliI], 1.0 * coefficients0[0], qubits!);
}
else{
ApplyDiagonalUnitary(coefficients0, BigEndian(qubits[1..Length(qubits)-1]));
else
{
ApplyDiagonalUnitary(coefficients0, BigEndian((qubits!)[1 .. Length(qubits!) - 1]));
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implementation step of multiply-controlled Z rotations.
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexZ
function MultiplexZComputeCoefficients_(coefficients: Double[]) : (Double[], Double[]) {
let newCoefficientsLength = Length(coefficients)/2;
function MultiplexZComputeCoefficients_ (coefficients : Double[]) : (Double[], Double[])
{
let newCoefficientsLength = Length(coefficients) / 2;
mutable coefficients0 = new Double[newCoefficientsLength];
mutable coefficients1 = new Double[newCoefficientsLength];
for(idxCoeff in 0..newCoefficientsLength-1){
for (idxCoeff in 0 .. newCoefficientsLength - 1)
{
set coefficients0[idxCoeff] = 0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength]);
set coefficients1[idxCoeff] = 0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength]);
}
return (coefficients0, coefficients1);
}
/// # Summary
/// Applies Multiply-controlled unitary operation $U$ that applies a
/// Applies Multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaries
/// Array of up to $2^n$ unitary operations. The $j$th operation
/// is indexed by the number state $\ket{j}$ encoded in big-endian format.
/// Array of up to $2^n$ unitary operations. The $j$th operation
/// is indexed by the number state $\ket{j}$ encoded in big-endian format.
///
/// ## index
/// $n$-qubit control register that encodes number states $\ket{j}$ in
@ -201,7 +231,7 @@ namespace Microsoft.Quantum.Canon
/// Generic qubit register that $V_j$ acts on.
///
/// # Remarks
/// `coefficients` will be padded with identity elements if
/// `coefficients` will be padded with identity elements if
/// fewer than $2^n$ are specified. This implementation uses
/// $n-1$ ancilla qubits.
///
@ -209,73 +239,97 @@ namespace Microsoft.Quantum.Canon
/// - Toward the first quantum simulation with quantum speedup
/// Andrew M. Childs, Dmitri Maslov, Yunseong Nam, Neil J. Ross, Yuan Su
/// https://arxiv.org/abs/1711.10980
operation MultiplexOperations<'T>(unitaries : ('T => () : Adjoint, Controlled)[], index: BigEndian, target: 'T) : () {
body{
if(Length(index) == 0){
fail "MultiplexOperations failed. Number of index qubits must be greater than 0.";
operation MultiplexOperations<'T> (unitaries : ('T => Unit : Adjoint, Controlled)[], index : BigEndian, target : 'T) : Unit
{
body (...)
{
if (Length(index!) == 0)
{
fail $"MultiplexOperations failed. Number of index qubits must be greater than 0.";
}
if(Length(unitaries) > 0){
if (Length(unitaries) > 0)
{
let ancilla = new Qubit[0];
MultiplexOperations_(unitaries, ancilla, index, target);
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Implementation step of MultiplexOperations.
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperations
operation MultiplexOperations_<'T>(unitaries : ('T => () : Adjoint, Controlled)[], ancilla: Qubit[], index: BigEndian, target: 'T) : () {
body{
let nIndex = Length(index);
let nStates = 2^nIndex;
operation MultiplexOperations_<'T> (unitaries : ('T => Unit : Adjoint, Controlled)[], ancilla : Qubit[], index : BigEndian, target : 'T) : Unit
{
body (...)
{
let nIndex = Length(index!);
let nStates = 2 ^ nIndex;
let nUnitaries = Length(unitaries);
let nUnitariesRight = MinI(nUnitaries, nStates/2);
let nUnitariesRight = MinI(nUnitaries, nStates / 2);
let nUnitariesLeft = MinI(nUnitaries, nStates);
let rightUnitaries = unitaries[0..(nUnitariesRight -1)];
let leftUnitaries = unitaries[nUnitariesRight..nUnitariesLeft - 1];
let newControls = BigEndian(index[1..nIndex-1]);
if(nUnitaries > 0){
if(Length(ancilla) == 1 && nIndex==0){
let rightUnitaries = unitaries[0 .. nUnitariesRight - 1];
let leftUnitaries = unitaries[nUnitariesRight .. nUnitariesLeft - 1];
let newControls = BigEndian((index!)[1 .. nIndex - 1]);
if (nUnitaries > 0)
{
if (Length(ancilla) == 1 && nIndex == 0)
{
// Termination case
(Controlled unitaries[0])(ancilla, target);
Controlled unitaries[0](ancilla, target);
}
elif(Length(ancilla) == 0 && nIndex>=1){
elif (Length(ancilla) == 0 && nIndex >= 1)
{
// Start case
let newAncilla = [index[0]];
if(nUnitariesLeft > 0){
let newAncilla = [(index!)[0]];
if (nUnitariesLeft > 0)
{
MultiplexOperations_(leftUnitaries, newAncilla, newControls, target);
}
X(newAncilla[0]);
MultiplexOperations_(rightUnitaries, newAncilla, newControls, target);
X(newAncilla[0]);
}
else{
else
{
// Recursion that reduces nIndex by 1 & sets Length(ancilla) to 1.
using(newAncilla = Qubit[1]){
(Controlled X)(ancilla + [index[0]], newAncilla[0]);
if(nUnitariesLeft > 0){
using (newAncilla = Qubit[1])
{
Controlled X(ancilla + [(index!)[0]], newAncilla[0]);
if (nUnitariesLeft > 0)
{
MultiplexOperations_(leftUnitaries, newAncilla, newControls, target);
}
(Controlled X)(ancilla, newAncilla[0]);
Controlled X(ancilla, newAncilla[0]);
MultiplexOperations_(rightUnitaries, newAncilla, newControls, target);
(Controlled X)(ancilla, newAncilla[0]);
(Controlled X)(ancilla + [index[0]], newAncilla[0]);
Controlled X(ancilla, newAncilla[0]);
Controlled X(ancilla + [(index!)[0]], newAncilla[0]);
}
}
}
}
adjoint auto
controlled (controlRegister) {
adjoint invert;
controlled (controlRegister, ...)
{
MultiplexOperations_(unitaries, controlRegister, index, target);
}
adjoint controlled auto
controlled adjoint invert;
}
}

Просмотреть файл

@ -1,10 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
open Microsoft.Quantum.Primitive;
/// # Summary
/// Measures the given Pauli operator using an explicit scratch
/// qubit to perform the measurement.
@ -19,55 +22,62 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// The result of measuring the given Pauli operator on
/// the `target` register.
operation MeasureWithScratch(pauli : Pauli[], target : Qubit[]) : Result
operation MeasureWithScratch (pauli : Pauli[], target : Qubit[]) : Result
{
body {
mutable result = Zero;
using (scratchRegister = Qubit[1]) {
let scratch = scratchRegister[0];
H(scratch);
for (idxPauli in 0..(Length(pauli) - 1)) {
let P = pauli[idxPauli];
let src = target[idxPauli];
if (P == PauliX) {
(Controlled X)([scratch], src);
} elif (P == PauliY) {
(Controlled Y)([scratch], src);
} elif (P == PauliZ) {
(Controlled Z)([scratch], src);
}
mutable result = Zero;
using (scratchRegister = Qubit[1])
{
let scratch = scratchRegister[0];
H(scratch);
for (idxPauli in 0 .. Length(pauli) - 1)
{
let P = pauli[idxPauli];
let src = target[idxPauli];
if (P == PauliX)
{
Controlled X([scratch], src);
}
elif (P == PauliY)
{
Controlled Y([scratch], src);
}
elif (P == PauliZ)
{
Controlled Z([scratch], src);
}
H(scratch);
set result = M(scratch);
ResetAll(scratchRegister);
}
return result;
H(scratch);
set result = M(scratch);
ResetAll(scratchRegister);
}
return result;
}
/// # Summary
/// Returns one of the single-qubit Pauli operators uniformly
/// at random.
///
/// # Output
/// A `Pauli` operator that is one of `[PauliI; PauliX; PauliY; PauliZ]`.
/// A `Pauli` operator that is one of `[PauliI, PauliX, PauliY, PauliZ]`.
///
/// # Remarks
/// This function calls <xref:microsoft.quantum.primitive.random>, so
/// its randomess depends on the implementation of `Random`.
operation RandomSingleQubitPauli() : Pauli {
body {
let probs = [0.5; 0.5; 0.5; 0.5];
let idxPauli = Random(probs);
let singleQubitPaulis = [PauliI; PauliX; PauliY; PauliZ];
return singleQubitPaulis[idxPauli];
}
operation RandomSingleQubitPauli () : Pauli
{
let probs = [0.5, 0.5, 0.5, 0.5];
let idxPauli = Random(probs);
let singleQubitPaulis = [PauliI, PauliX, PauliY, PauliZ];
return singleQubitPaulis[idxPauli];
}
/// # Summary
/// Given a multi-qubit Pauli operator, applies the corresponding operation to
/// a register.
@ -81,36 +91,42 @@ namespace Microsoft.Quantum.Canon {
/// # Example
/// The following are equivalent:
/// ```Q#
/// ApplyPauli([PauliY; PauliZ; PauliX], target);
/// ApplyPauli([PauliY, PauliZ, PauliX], target);
///
/// Y(target[0]);
/// Z(target[1]);
/// X(target[2]);
/// ```
operation ApplyPauli(pauli : Pauli[], target : Qubit[]) : ()
operation ApplyPauli (pauli : Pauli[], target : Qubit[]) : Unit
{
body {
for (idxPauli in 0..(Length(pauli) - 1)) {
body (...)
{
for (idxPauli in 0 .. Length(pauli) - 1)
{
let P = pauli[idxPauli];
let targ = target[idxPauli];
if (P == PauliX) {
if (P == PauliX)
{
X(targ);
}
elif (P == PauliY) {
elif (P == PauliY)
{
Y(targ);
}
elif (P == PauliZ) {
elif (P == PauliZ)
{
Z(targ);
}
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Given a bit string, returns a multi-qubit Pauli operator
/// represented as an array of single-qubit Pauli operators.
@ -127,21 +143,27 @@ namespace Microsoft.Quantum.Canon {
///
/// # Remarks
/// The Boolean array and the quantum register must be of equal length.
function PauliFromBitString(pauli : Pauli, bitApply: Bool, bits : Bool[]) : Pauli[] {
function PauliFromBitString (pauli : Pauli, bitApply : Bool, bits : Bool[]) : Pauli[]
{
let nBits = Length(bits);
mutable paulis = new Pauli[nBits];
for (idxBit in 0..nBits - 1) {
if (bits[idxBit] == bitApply) {
for (idxBit in 0 .. nBits - 1)
{
if (bits[idxBit] == bitApply)
{
set paulis[idxBit] = pauli;
} else {
}
else
{
set paulis[idxBit] = PauliI;
}
}
return paulis;
}
/// # Summary
/// Applies a Pauli operator on the $n^{\text{th}}$ qubit if the $n^{\text{th}}$
/// bit of a Boolean array matches a given input.
@ -158,24 +180,28 @@ namespace Microsoft.Quantum.Canon {
///
/// # Remarks
/// The Boolean array and the quantum register must be of equal length
///
operation ApplyPauliFromBitString(pauli : Pauli, bitApply: Bool, bits : Bool[], qubits : Qubit[]) : ()
operation ApplyPauliFromBitString (pauli : Pauli, bitApply : Bool, bits : Bool[], qubits : Qubit[]) : Unit
{
body {
body (...)
{
let nBits = Length(bits);
//FailOn (nbits != Length(qubits), "Number of control bits must be equal to number of control qubits")
for (idxBit in 0..nBits - 1) {
if (bits[idxBit] == bitApply) {
for (idxBit in 0 .. nBits - 1)
{
if (bits[idxBit] == bitApply)
{
ApplyPauli([pauli], [qubits[idxBit]]);
}
}
}
adjoint auto
controlled auto
adjoint controlled auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Given an array of multi-qubit Pauli operators, measures each using a specified measurement
/// gadget, then returns the array of results.
@ -191,19 +217,19 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// The array of results obtained from measuring each element of `paulis`
/// on `target`.
operation MeasurePaulis(paulis : Pauli[][], target : Qubit[], gadget : ((Pauli[], Qubit[]) => Result)) : Result[]
operation MeasurePaulis (paulis : Pauli[][], target : Qubit[], gadget : ((Pauli[], Qubit[]) => Result)) : Result[]
{
body {
mutable results = new Result[Length(paulis)];
for (idxPauli in 0..(Length(paulis) - 1)) {
set results[idxPauli] = gadget(paulis[idxPauli], target);
}
return results;
mutable results = new Result[Length(paulis)];
for (idxPauli in 0 .. Length(paulis) - 1)
{
set results[idxPauli] = gadget(paulis[idxPauli], target);
}
return results;
}
/// # Summary
/// Given a single-qubit Pauli operator and the index of a qubit,
/// returns a multi-qubit Pauli operator with the given single-qubit
@ -219,26 +245,33 @@ namespace Microsoft.Quantum.Canon {
/// Length of the array to be returned.
///
/// # Example
/// To obtain the array `[PauliI; PauliI; PauliX; PauliI]`:
/// To obtain the array `[PauliI, PauliI, PauliX, PauliI]`:
/// ```qsharp
/// EmbedPauli(PauliX, 2, 3);
/// ```
function EmbedPauli(pauli : Pauli, location : Int, n : Int) : Pauli[]
function EmbedPauli (pauli : Pauli, location : Int, n : Int) : Pauli[]
{
mutable pauliArray = new Pauli[n];
for (index in 0..(n-1)) {
if (index == location) {
for (index in 0 .. n - 1)
{
if (index == location)
{
set pauliArray[index] = pauli;
}
else {
else
{
set pauliArray[index] = PauliI;
}
}
return pauliArray;
}
// FIXME: Remove in favor of something that computes arbitrary
// weight Paulis.
/// # Summary
/// Returns an array of all weight-1 Pauli operators
/// on a given number of qubits.
@ -251,30 +284,39 @@ namespace Microsoft.Quantum.Canon {
/// # Output
/// An array of multi-qubit Pauli operators, each of which is
/// represented as an array with length `nQubits`.
function WeightOnePaulis(nQubits : Int) : Pauli[][] {
mutable paulis = new (Pauli[])[3 * nQubits];
let pauliGroup = [PauliX; PauliY; PauliZ];
for (idxQubit in 0..nQubits - 1) {
for (idxPauli in 0..Length(pauliGroup) - 1) {
function WeightOnePaulis (nQubits : Int) : Pauli[][]
{
mutable paulis = new Pauli[][3 * nQubits];
let pauliGroup = [PauliX, PauliY, PauliZ];
for (idxQubit in 0 .. nQubits - 1)
{
for (idxPauli in 0 .. Length(pauliGroup) - 1)
{
set paulis[idxQubit * Length(pauliGroup) + idxPauli] = EmbedPauli(pauliGroup[idxPauli], idxQubit, nQubits);
}
}
return paulis;
}
// NB: This operation is intended to be private to Paulis.qs.
operation _BasisChangeZtoY(target : Qubit) : () {
body {
operation _BasisChangeZtoY (target : Qubit) : Unit
{
body (...)
{
H(target);
S(target);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
/// # Summary
/// Measures each qubit in a given array in the standard basis.
/// # Input
@ -282,19 +324,21 @@ namespace Microsoft.Quantum.Canon {
/// An array of qubits to be measured.
/// # Output
/// An array of measurement results.
operation MultiM(targets : Qubit[]) : Result[]
operation MultiM (targets : Qubit[]) : Result[]
{
body{
mutable results = new Result[Length(targets)];
for(idxQubit in 0..Length(targets)-1){
set results[idxQubit] = M(targets[idxQubit]);
}
return results;
mutable results = new Result[Length(targets)];
for (idxQubit in 0 .. Length(targets) - 1)
{
set results[idxQubit] = M(targets[idxQubit]);
}
return results;
}
/// # Summary
/// Measures a single qubit in the $Z$ basis,
/// Measures a single qubit in the $Z$ basis,
/// and resets it to the standard basis state
/// $\ket{0}$ following the measurement.
///
@ -304,21 +348,24 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The result of measuring `target` in the Pauli $Z$ basis.
operation MResetZ(target : Qubit) : Result {
body {
let result = M(target);
if (result == One) {
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
operation MResetZ (target : Qubit) : Result
{
let result = M(target);
if (result == One)
{
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
}
/// # Summary
/// Measures a single qubit in the $X$ basis,
/// Measures a single qubit in the $X$ basis,
/// and resets it to the standard basis state
/// $\ket{0}$ following the measurement.
///
@ -328,23 +375,27 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The result of measuring `target` in the Pauli $X$ basis.
operation MResetX(target : Qubit) : Result {
body {
let result = Measure([PauliX], [target]);
// We must return the qubit to the Z basis as well.
H(target);
if (result == One) {
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
operation MResetX (target : Qubit) : Result
{
let result = Measure([PauliX], [target]);
// We must return the qubit to the Z basis as well.
H(target);
if (result == One)
{
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
}
/// # Summary
/// Measures a single qubit in the $Y$ basis,
/// Measures a single qubit in the $Y$ basis,
/// and resets it to the standard basis state
/// $\ket{0}$ following the measurement.
///
@ -354,22 +405,25 @@ namespace Microsoft.Quantum.Canon {
///
/// # Output
/// The result of measuring `target` in the Pauli $Y$ basis.
operation MResetY(target : Qubit) : Result {
body {
let result = Measure([PauliY], [target]);
// We must return the qubit to the Z basis as well.
(Adjoint _BasisChangeZtoY)(target);
if (result == One) {
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
operation MResetY (target : Qubit) : Result
{
let result = Measure([PauliY], [target]);
// We must return the qubit to the Z basis as well.
Adjoint _BasisChangeZtoY(target);
if (result == One)
{
// Recall that the +1 eigenspace of a measurement operator corresponds to
// the Result case Zero. Thus, if we see a One case, we must reset the state
// have +1 eigenvalue.
X(target);
}
return result;
}
/// # Summary
/// Applies the Hadamard transformation $H_Y = S H$
/// between the $Z$ and $Y$ bases to a single qubit,
@ -388,14 +442,19 @@ namespace Microsoft.Quantum.Canon {
/// Qubit to which the gate should be applied.
///
/// # See Also
operation HY(target : Qubit) : () {
body {
operation HY (target : Qubit) : Unit
{
body (...)
{
H(target);
S(target);
}
adjoint auto
controlled auto
controlled adjoint auto
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -1,20 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// The `IsResultZero` function tests if a given Result value is equal to `Zero`.
/// The `IsResultZero` function tests if a given Result value is equal to `Zero`.
///
/// # Input
/// ## input
/// `Result` value to be tested.
/// # Output
/// Returns `true` if `input` is equal to `Zero`.
function IsResultZero (input : Result) : Bool {
return (input == Zero);
function IsResultZero (input : Result) : Bool
{
return input == Zero;
}
/// # Summary
/// The `IsResultOne` function tests if a given Result value is equal to `One`.
///
@ -23,8 +27,11 @@ namespace Microsoft.Quantum.Canon {
/// `Result` value to be tested.
/// # Output
/// Returns `true` if `input` is equal to `One`.
function IsResultOne (input : Result) : Bool {
return (input == One);
function IsResultOne (input : Result) : Bool
{
return input == One;
}
}

63
Canon/src/Utils/Ranges.qs Normal file
Просмотреть файл

@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Returns the absolute value of an integer.
///
/// # Input
/// ## input
/// An integer $x$ of type `Int`.
///
/// # Output
/// An integer $|x|$ of type `Int`.
function IntAbs (input : Int) : Int
{
mutable tmp = 0;
if (input < 0)
{
set tmp = -input;
}
else
{
set tmp = input;
}
return tmp;
}
/// # Summary
/// Returns the maximum of two integers.
///
/// # Input
/// ## a
/// An integer $a$ of type `Int`.
/// ## b
/// An integer $b$ of type `Int`.
///
/// # Output
/// An integer $\max{a,b}$ of type `Int`.
function IntMax (a : Int, b : Int) : Int
{
mutable tmp = 0;
if (a < b)
{
set tmp = b;
}
else
{
set tmp = a;
}
return tmp;
}
}

Просмотреть файл

@ -1,89 +1,104 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
namespace Microsoft.Quantum.Canon
{
/// # Summary
/// Converts a `Result` type to a `Bool` type, where `One` is mapped to
/// Converts a `Result` type to a `Bool` type, where `One` is mapped to
/// `true` and `Zero` is mapped to `false`.
///
/// # Input
/// ## input
/// `Result` to be converted.
///
///
/// # Output
/// A `Bool` representing the `input`.
function BoolFromResult( input: Result) : Bool
function BoolFromResult (input : Result) : Bool
{
if(input == Zero) {
if (input == Zero)
{
return false;
}
else {
else
{
return true;
}
}
/// # Summary
/// Converts a `Bool` type to a `Result` type, where `true` is mapped to
/// Converts a `Bool` type to a `Result` type, where `true` is mapped to
/// `One` and `false` is mapped to `Zero`.
///
/// # Input
/// ## input
/// `Bool` to be converted.
///
///
/// # Output
/// A `Result` representing the `input`.
function ResultFromBool( input: Bool) : Result
function ResultFromBool (input : Bool) : Result
{
if(input == false) {
if (input == false)
{
return Zero;
}
else {
else
{
return One;
}
}
/// # Summary
/// Converts a `Result[]` type to a `Bool[]` type, where `One` is mapped to
/// # Summary
/// Converts a `Result[]` type to a `Bool[]` type, where `One` is mapped to
/// `true` and `Zero` is mapped to `false`.
///
/// # Input
/// ## input
/// `Result[]` to be converted.
///
///
/// # Output
/// A `Bool[]` representing the `input`.
function BoolArrFromResultArr(input : Result[]) : Bool[]
function BoolArrFromResultArr (input : Result[]) : Bool[]
{
let nInput = Length(input);
mutable output = new Bool[nInput];
for (idx in 0..nInput - 1) {
for (idx in 0 .. nInput - 1)
{
set output[idx] = BoolFromResult(input[idx]);
}
return output;
}
/// # Summary
/// Converts a `Bool[]` type to a `Result[]` type, where `true` is mapped to
/// Converts a `Bool[]` type to a `Result[]` type, where `true` is mapped to
/// `One` and `false` is mapped to `Zero`.
///
/// # Input
/// ## input
/// `Bool[]` to be converted.
///
///
/// # Output
/// A `Result[]` representing the `input`.
function ResultArrFromBoolArr(input : Bool[]) : Result[]
function ResultArrFromBoolArr (input : Bool[]) : Result[]
{
let nInput = Length(input);
mutable output = new Result[nInput];
for (idx in 0..nInput - 1) {
for (idx in 0 .. nInput - 1)
{
set output[idx] = ResultFromBool(input[idx]);
}
return output;
}
/// # Summary
/// Produces binary representation of positive integer in little Endian format.
///
@ -92,69 +107,77 @@ namespace Microsoft.Quantum.Canon {
/// Positive integer.
/// ## bits
/// Bits in binary representation of number.
///
///
/// # Remarks
/// The input `number` must be at most 2^bits -1.
function BoolArrFromPositiveInt(number : Int, bits : Int) : Bool[]
function BoolArrFromPositiveInt (number : Int, bits : Int) : Bool[]
{
AssertBoolEqual(
(number >= 0) && ( number < 2^bits ), true,
"`number` must be between 0 and 2^`bits` - 1" );
AssertBoolEqual(number >= 0 && number < 2 ^ bits, true, $"`number` must be between 0 and 2^`bits` - 1");
mutable outputBits = new Bool[bits];
mutable tempInt = number;
for ( idxBit in 0..bits - 1 ) {
if ( tempInt % 2 == 0 ){
for (idxBit in 0 .. bits - 1)
{
if (tempInt % 2 == 0)
{
set outputBits[idxBit] = false;
}
else {
else
{
set outputBits[idxBit] = true;
}
set tempInt = tempInt / 2;
}
return outputBits;
}
/// # Summary
/// Produces a positive integer from a string of bits in in little Endian format.
///
/// # Input
/// ## bits
/// Bits in binary representation of number.
function PositiveIntFromBoolArr(bits : Bool[]) : Int
function PositiveIntFromBoolArr (bits : Bool[]) : Int
{
AssertBoolEqual(
Length(bits) < 64, true,
"`Length(bits)` must be less than 64" );
AssertBoolEqual(Length(bits) < 64, true, $"`Length(bits)` must be less than 64");
mutable number = 0;
let nBits = Length(bits) ;
for ( idxBit in 0..nBits - 1 ) {
if (bits[idxBit]) {
let nBits = Length(bits);
for (idxBit in 0 .. nBits - 1)
{
if (bits[idxBit])
{
set number = number + 2 ^ idxBit;
}
}
return number;
}
/// # Summary
/// Produces a positive integer from a string of Results in in little Endian format.
///
/// # Input
/// ## results
/// Results in binary representation of number.
function PositiveIntFromResultArr(results :Result[]) : Int
function PositiveIntFromResultArr (results : Result[]) : Int
{
return PositiveIntFromBoolArr(BoolArrFromResultArr(results));
}
/// # Summary
/// # Summary
/// Used to cast UDTs that are derived from type Qubit[] down to Qubit[].
/// Handy when used with generic functions like Head and Tail.
function AsQubitArray( arr : Qubit[] ) : Qubit[] {
function AsQubitArray (arr : Qubit[]) : Qubit[]
{
return arr;
}
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
///Here we consider the smallest example of amplitude amplification
///Suppose we have a single-qubit oracle that prepares the state
/// O |0> = \lambda |1> + \sqrt{1-|\lambda|^2} |0>
/// The goal is to amplify the |1> state
/// We can do this either by synthesizing the reflection about the start and target states ourselves,
/// We can also do it by passing the oracle for state preparation
operation ExampleStatePrepImpl (lambda : Double, idxFlagQubit : Int, qubitStart : Qubit[]) : Unit {
body (...) {
let rotAngle = 2.0 * ArcSin(lambda);
Ry(rotAngle, qubitStart[idxFlagQubit]);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
function ExampleStatePrep (lambda : Double) : StateOracle {
return StateOracle(ExampleStatePrepImpl(lambda, _, _));
}
/// In this minimal example, there are no system qubits, only a single flag qubit.
/// ExampleStatePrep is already of type StateOracle, so we call
/// AmpAmpByOracle(iterations: Int, stateOracle : StateOracle, idxFlagQubit : Int startQubits: Qubit[]) : ()
operation AmpAmpByOracleTest () : Unit {
using (qubits = Qubit[1]) {
ResetAll(qubits);
for (nIterations in 0 .. 5) {
for (idx in 1 .. 20) {
let lambda = ToDouble(idx) / 20.0;
let rotAngle = ArcSin(lambda);
let idxFlag = 0;
let startQubits = qubits;
let stateOracle = ExampleStatePrep(lambda);
(AmpAmpByOracle(nIterations, stateOracle, idxFlag))(startQubits);
let successAmplitude = Sin(ToDouble(2 * nIterations + 1) * rotAngle);
let successProbability = successAmplitude * successAmplitude;
AssertProb([PauliZ], [startQubits[idxFlag]], One, successProbability, $"Error: Success probability does not match theory", 1E-10);
ResetAll(qubits);
}
}
}
}
operation AmpAmpObliviousByOraclePhasesTest () : Unit {
using (qubits = Qubit[1]) {
ResetAll(qubits);
for (nIterations in 0 .. 5) {
let phases = AmpAmpPhasesStandard(nIterations);
for (idx in 0 .. 20) {
let rotAngle = (ToDouble(idx) * PI()) / 20.0;
let idxFlag = 0;
let ancillaRegister = qubits;
let systemRegister = new Qubit[0];
let ancillaOracle = DeterministicStateOracle(Exp([PauliY], rotAngle * 0.5, _));
let signalOracle = ObliviousOracle(NoOp<(Qubit[], Qubit[])>(_, _));
(AmpAmpObliviousByOraclePhases(phases, ancillaOracle, signalOracle, idxFlag))(ancillaRegister, systemRegister);
let successAmplitude = Sin((ToDouble(2 * nIterations + 1) * rotAngle) * 0.5);
let successProbability = successAmplitude * successAmplitude;
AssertProb([PauliZ], [ancillaRegister[idxFlag]], One, successProbability, $"Error: Success probability does not match theory", 1E-10);
ResetAll(qubits);
}
}
}
}
operation AmpAmpTargetStateReflectionOracleTest () : Unit {
using (qubits = Qubit[1]) {
ResetAll(qubits);
for (idx in 0 .. 20) {
let rotangle = (ToDouble(idx) * PI()) / 20.0;
let targetStateReflection = TargetStateReflectionOracle(0);
let success = Cos(0.5 * rotangle) * Cos(0.5 * rotangle);
H(qubits[0]);
targetStateReflection!(rotangle, qubits);
AssertProb([PauliX], qubits, Zero, success, $"Error: Success probability does not match theory", 1E-10);
ResetAll(qubits);
}
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Testing;
/// # Summary
/// Tests multiply controlled not implementation that uses
/// ApplyMultiControlledCA against multiply controlled version of
/// the Microsoft.Quantum.Primitive.X
operation ApplyMultiControlledTest () : Unit {
let twoQubitOp = CNOT;
// this gives us operation ( controls : Qubit[], targets : Qubit[] ) => ()
// where we expect targets to have length 2
let multiControlledCNOT = Controlled (ApplyToFirstTwoQubitsCA(twoQubitOp, _));
// this gives up operation ( qubits : Qubit[] ) => ()
// where first qubit in qubits is control and the rest are target for
// twoQubitOp
let singlyControlledCNOT = ApplyToPartitionCA(multiControlledCNOT, 1, _);
// Construct multiply controlled op using its singly controlled version
// with the help of ApplyMultiControlledCA
let canonMultiNot = ApplyMultiControlledCA(singlyControlledCNOT, CCNOTop(CCNOT), _, _);
for (numberOfcontrols in 1 .. 5) {
Message($"Checking the equality with {numberOfcontrols} controls");
// construct actual and expected with desired number of controls
let actual = ApplyToPartitionCA(canonMultiNot, numberOfcontrols, _);
let expected = ApplyToPartitionCA(multiControlledCNOT, numberOfcontrols, _);
// check equality
AssertOperationsEqualReferenced(actual, expected, numberOfcontrols + 2);
}
}
}

Просмотреть файл

@ -0,0 +1,170 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
operation InPlaceXorTestHelper (testValue : Int, numberOfQubits : Int) : Unit {
using (register = Qubit[numberOfQubits]) {
let registerLE = LittleEndian(register);
InPlaceXorLE(testValue, registerLE);
let measuredValue = MeasureInteger(registerLE);
AssertIntEqual(testValue, measuredValue, $"Did not measure the integer we expected.");
}
}
operation InPlaceXorLETest () : Unit {
ApplyToEach(InPlaceXorTestHelper, [(63, 6), (42, 6)]);
}
operation IntegerIncrementLETestHelper (summand1 : Int, summand2 : Int, numberOfQubits : Int) : Unit {
using (register = Qubit[numberOfQubits]) {
let registerLE = LittleEndian(register);
InPlaceXorLE(summand1, registerLE);
IntegerIncrementLE(summand2, registerLE);
let expected = Modulus(summand1 + summand2, 2 ^ numberOfQubits);
let actual = MeasureInteger(registerLE);
AssertIntEqual(expected, actual, $"Expected {expected}, got {actual}");
}
}
/// # Summary
/// Exhaustively tests Microsoft.Quantum.Canon.IntegerIncrementLE
/// on 4 qubits
operation IntegerIncrementLETest () : Unit {
let numberOfQubits = 4;
for (summand1 in 0 .. 2 ^ numberOfQubits - 1) {
for (summand2 in -2 ^ numberOfQubits .. 2 ^ numberOfQubits) {
IntegerIncrementLETestHelper(summand1, summand2, numberOfQubits);
}
}
}
operation ModularIncrementLETestHelper (summand1 : Int, summand2 : Int, modulus : Int, numberOfQubits : Int) : Unit {
using (register = Qubit[numberOfQubits]) {
let registerLE = LittleEndian(register);
InPlaceXorLE(summand1, registerLE);
ModularIncrementLE(summand2, modulus, registerLE);
let expected = Modulus(summand1 + summand2, modulus);
let actual = MeasureInteger(registerLE);
AssertIntEqual(expected, actual, $"Expected {expected}, got {actual}");
using (controls = Qubit[2]) {
InPlaceXorLE(summand1, registerLE);
Controlled ModularIncrementLE(controls, (summand2, modulus, registerLE));
let actual2 = MeasureInteger(registerLE);
AssertIntEqual(summand1, actual2, $"Expected {summand1}, got {actual2}");
// now set all controls to 1
InPlaceXorLE(summand1, registerLE);
(ControlledOnInt(0, ModularIncrementLE(summand2, modulus, _)))(controls, registerLE);
let actual3 = MeasureInteger(registerLE);
AssertIntEqual(expected, actual3, $"Expected {expected}, got {actual3}");
// restore controls back to |0⟩
}
}
}
/// # Summary
/// Exhaustively tests Microsoft.Quantum.Canon.ModularIncrementLE
/// on 4 qubits with modulus 13
operation ModularIncrementLETest () : Unit {
let numberOfQubits = 4;
let modulus = 13;
for (summand1 in 0 .. modulus - 1) {
for (summand2 in 0 .. modulus - 1) {
ModularIncrementLETestHelper(summand1, summand2, modulus, numberOfQubits);
}
}
}
operation ModularAddProductLETestHelper (summand : Int, multiplier1 : Int, multiplier2 : Int, modulus : Int, numberOfQubits : Int) : Unit {
using (register = Qubit[numberOfQubits * 2]) {
let summandLE = LittleEndian(register[0 .. numberOfQubits - 1]);
let multiplierLE = LittleEndian(register[numberOfQubits .. 2 * numberOfQubits - 1]);
InPlaceXorLE(summand, summandLE);
InPlaceXorLE(multiplier1, multiplierLE);
ModularAddProductLE(multiplier2, modulus, multiplierLE, summandLE);
let expected = Modulus(summand + multiplier1 * multiplier2, modulus);
let actual = MeasureInteger(summandLE);
let actualMult = MeasureInteger(multiplierLE);
AssertIntEqual(expected, actual, $"Expected {expected}, got {actual}");
AssertIntEqual(multiplier1, actualMult, $"Expected {multiplier1}, got {actualMult}");
}
}
/// # Summary
/// Exhaustively tests Microsoft.Quantum.Canon.ModularAddProductLE
/// on 4 qubits with modulus 13
operation ModularAddProductLETest () : Unit {
let numberOfQubits = 4;
let modulus = 13;
for (summand in 0 .. modulus - 1) {
for (multiplier1 in 0 .. modulus - 1) {
for (multiplier2 in 0 .. modulus - 1) {
ModularAddProductLETestHelper(summand, multiplier1, multiplier2, modulus, numberOfQubits);
}
}
}
}
operation ModularMultiplyByConstantLETestHelper (multiplier1 : Int, multiplier2 : Int, modulus : Int, numberOfQubits : Int) : Unit {
using (register = Qubit[numberOfQubits]) {
if (IsCoprime(multiplier2, modulus)) {
let multiplierLE = LittleEndian(register);
InPlaceXorLE(multiplier1, multiplierLE);
ModularMultiplyByConstantLE(multiplier2, modulus, multiplierLE);
let expected = Modulus(multiplier1 * multiplier2, modulus);
let actualMult = MeasureInteger(multiplierLE);
AssertIntEqual(expected, actualMult, $"Expected {expected}, got {actualMult}");
}
}
}
/// # Summary
/// Exhaustively tests Microsoft.Quantum.Canon.ModularMultiplyByConstantLE
/// on 4 qubits with modulus 13
operation ModularMultiplyByConstantLETest () : Unit {
let numberOfQubits = 4;
let modulus = 13;
for (multiplier1 in 0 .. modulus - 1) {
for (multiplier2 in 0 .. modulus - 1) {
ModularMultiplyByConstantLETestHelper(multiplier1, multiplier2, modulus, numberOfQubits);
}
}
}
}

107
Canon/tests/ArrayTests.qs Normal file
Просмотреть файл

@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
function ZipTest () : Unit {
let left = [1, 2, 101];
let right = [PauliY, PauliI];
let zipped = Zip(left, right);
let (leftActual1, rightActual1) = zipped[0];
if (leftActual1 != 1 || rightActual1 != PauliY) {
fail $"Expected (1, PauliY), got ({leftActual1}, {rightActual1}).";
}
let (leftActual2, rightActual2) = zipped[1];
if (leftActual2 != 2 || rightActual2 != PauliI) {
fail $"Expected (2, PauliI), got ({leftActual2}, {rightActual2}).";
}
}
function LookupTest () : Unit {
let array = [1, 12, 71, 103];
let fn = LookupFunction(array);
AssertIntEqual(fn(0), 1, $"fn(0) did not return array[0]");
// Make sure we can call in random order!
AssertIntEqual(fn(3), 103, $"fn(3) did not return array[3]");
AssertIntEqual(fn(2), 71, $"fn(2) did not return array[2]");
AssertIntEqual(fn(1), 12, $"fn(1) did not return array[1]");
}
function ConstantArrayTestHelper (x : Int) : Int {
return x * x;
}
function ConstantArrayTest () : Unit {
let dblArray = ConstantArray(71, 2.17);
AssertIntEqual(Length(dblArray), 71, $"ConstantArray(Int, Double) had the wrong length.");
let ignore = Map(AssertAlmostEqual(_, 2.17), dblArray);
// Stress test by making an array of Int -> Int.
let fnArray = ConstantArray(7, ConstantArrayTestHelper);
AssertIntEqual(Length(fnArray), 7, $"ConstantArray(Int, Int -> Int) had the wrong length.");
AssertIntEqual(fnArray[3](7), 49, $"ConstantArray(Int, Int -> Int) had the wrong value.");
}
function SubarrayTest () : Unit {
let array0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let subarrayOdd = Subarray([1, 3, 5, 7, 9], array0);
let subarrayEven = Subarray([0, 2, 4, 6, 8, 10], array0);
AssertBoolEqual(ForAll(IsEven, subarrayEven), true, $"the even elements of [1..10] were not correctly sliced.");
AssertBoolEqual(ForAny(IsEven, subarrayOdd), false, $"the odd elements of [1..10] were not correctly sliced.");
let array1 = [10, 11, 12, 13];
Ignore(Map(AssertIntEqual(_, _, $"Subarray failed: subpermutation case."), Zip([12, 11], Subarray([2, 1], array1))));
}
function FilterTest () : Unit {
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let evenArray = Filter(IsEven, array);
AssertBoolEqual(ForAll(IsEven, evenArray), true, $"the even elements of [1..10] were not correctly filtered.");
}
function ReverseTest () : Unit {
let array = [1, 2, 3];
Ignore(Map(AssertIntEqual(_, _, $"Reverse failed."), Zip([3, 2, 1], Reverse(array))));
}
function ExcludeTest () : Unit {
let array = [10, 11, 12, 13, 14, 15];
Ignore(Map(AssertIntEqual(_, _, $"Exclude failed."), Zip([10, 11, 13, 14], Exclude([2, 5], array))));
}
function PadTest () : Unit {
mutable arrayTestCase = [(-5, 2, [10, 11, 12], [10, 11, 12, 2, 2]), (5, 2, [10, 11, 12], [2, 2, 10, 11, 12]), (-3, -2, [10, 11, 12], [10, 11, 12])];
for (idxTest in 0 .. Length(arrayTestCase) - 1) {
let (nElementsTotal, defaultElement, inputArray, outputArray) = arrayTestCase[idxTest];
let paddedArray = Pad(nElementsTotal, defaultElement, inputArray);
Ignore(Map(AssertIntEqual(_, _, $"Pad failed."), Zip(outputArray, paddedArray)));
}
}
}

134
Canon/tests/AssertTests.qs Normal file
Просмотреть файл

@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// This file contains very simple tests that should trivially pass
// with the intent of testing the assert and testing harness mechanisms themselves.
operation EmptyTest () : Unit {
}
operation PreparationTest () : Unit {
using (qubits = Qubit[1]) {
AssertProb([PauliZ], [qubits[0]], Zero, 1.0, $"Freshly prepared qubit was not in |0〉 state.", 1E-10);
}
}
operation OperationTestShouldFail () : Unit {
fail $"OK";
}
function FunctionTestShouldFail () : Unit {
fail $"OK";
}
function AssertEqualTestShouldFail () : Unit {
AssertAlmostEqual(1.0, 0.0);
}
function AssertBoolArrayEqualTestShouldFail () : Unit {
AssertBoolArrayEqual([true, false], [false, true], $"OK");
}
function AssertBoolEqualTestShouldFail () : Unit {
AssertBoolEqual(true, false, $"OK");
}
function AssertResultEqualTestShouldFail () : Unit {
AssertResultEqual(Zero, One, $"OK");
}
function AssertIntEqualTestShouldFail () : Unit {
AssertIntEqual(12, 42, $"OK");
}
/// # Summary
/// Tests whether common builtin operations are self adjoint.
/// These tests are already performed in Solid itself, such that
/// this operation tests whether we can reproduce that using our
/// operation equality assertions.
operation SelfAdjointOperationsTest () : Unit {
let ops = [I, X, Y, Z, H];
for (idxOp in 0 .. Length(ops) - 1) {
AssertOperationsEqualReferenced(ApplyToEach(ops[idxOp], _), ApplyToEachA(ops[idxOp], _), 3);
}
}
/// # Summary
/// Performs the same test as SelfAdjointOperationsTest,
/// but using Bind to gather the self-adjoint operations.
///
/// # Remarks
/// Marked as ex-fail due to known issues with Bind.
operation BindSelfAdjointOperationsTestExFail () : Unit {
let ops = [I, X, Y, Z, H];
for (idxOp in 0 .. Length(ops) - 1) {
let arr = [ops[idxOp], Adjoint ops[idxOp]];
let bound = BindCA(arr);
AssertOperationsEqualReferenced(ApplyToEachCA(BindCA(arr), _), ApplyToEachA(I, _), 3);
}
}
operation AssertProbIntTest () : Unit {
let theta = 0.123;
let prob = 0.015052858190174602;
let tolerance = 1E-09;
using (qubits = Qubit[4]) {
X(qubits[0]);
X(qubits[2]);
Exp([PauliX], theta, [qubits[3]]);
AssertProbInt(5, 1.0 - prob, LittleEndian(qubits), tolerance);
AssertProbInt(13, prob, LittleEndian(qubits), tolerance);
AssertProbIntBE(10, 1.0 - prob, BigEndian(qubits), tolerance);
AssertProbIntBE(11, prob, BigEndian(qubits), tolerance);
ResetAll(qubits);
}
}
operation AssertPhaseTest () : Unit {
let phase = 0.456;
let tolerance = 1E-09;
using (qubits = Qubit[1]) {
H(qubits[0]);
Exp([PauliZ], phase, qubits);
AssertPhase(phase, qubits[0], tolerance);
ResetAll(qubits);
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<NoWarn>0162</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\src\Canon.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,219 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Testing;
function ComposeTest () : Unit {
let target = [3, 17, 2];
AssertIntEqual((Compose(Modulus(_, 14), Max))(target), 3, $"Compose(Modulus(_, 14), Max) did not return expected result.");
}
operation WithTest () : Unit {
let actual = With(H, X, _);
let expected = Z;
AssertOperationsEqualReferenced(ApplyToEach(actual, _), ApplyToEachA(expected, _), 4);
}
// Make sure that if CurryTest fails, it's because of Curry and not
// something else.
operation CurryPreTest () : Unit {
AssertOperationsEqualInPlace(Exp([PauliZ], 1.7, _), Exp([PauliZ], 1.7, _), 1);
AssertOperationsEqualReferenced(Exp([PauliZ], 1.7, _), Exp([PauliZ], 1.7, _), 1);
}
operation CurryTest () : Unit {
let curried = CurryOp(Exp([PauliZ], _, _));
AssertOperationsEqualInPlace(curried(1.7), Exp([PauliZ], 1.7, _), 1);
AssertOperationsEqualReferenced(curried(1.7), Exp([PauliZ], 1.7, _), 1);
}
operation BindTest () : Unit {
let bound = BindCA([H, X, H]);
AssertOperationsEqualReferenced(ApplyToEach(bound, _), ApplyToEachA(Z, _), 3);
}
function StripControlled<'T> (op : ('T => Unit : Adjoint, Controlled)) : ('T => Unit : Adjoint) {
return op;
}
operation BindATest () : Unit {
let bound = BindA(Map(StripControlled<Qubit>, [T, T]));
AssertOperationsEqualReferenced(ApplyToEach(bound, _), ApplyToEachA(S, _), 3);
AssertOperationsEqualReferenced(ApplyToEach(Adjoint bound, _), ApplyToEachA(Adjoint S, _), 3);
}
operation BindCTestHelper0 (op : (Qubit => Unit : Controlled), qubits : Qubit[]) : Unit {
Controlled op([qubits[0]], qubits[1]);
}
operation BindCTestHelper1 (op : (Qubit => Unit : Adjoint, Controlled), qubits : Qubit[]) : Unit {
body (...) {
Controlled op([qubits[0]], qubits[1]);
}
adjoint invert;
}
function StripAdjoint<'T> (op : ('T => Unit : Adjoint, Controlled)) : ('T => Unit : Controlled) {
return op;
}
operation BindCTest () : Unit {
let stripped = Map(StripAdjoint<Qubit>, [T, T]);
let bound = BindC(stripped);
AssertOperationsEqualReferenced(ApplyToEach(bound, _), ApplyToEachA(S, _), 3);
let op = BindCTestHelper0(bound, _);
let target = BindCTestHelper1(S, _);
AssertOperationsEqualReferenced(op, target, 6);
}
operation BindCATest () : Unit {
let bound = BindCA([T, T]);
AssertOperationsEqualReferenced(ApplyToEach(bound, _), ApplyToEachA(S, _), 3);
AssertOperationsEqualReferenced(ApplyToEach(Adjoint bound, _), ApplyToEachA(Adjoint S, _), 3);
let op = BindCTestHelper0(Adjoint bound, _);
let target = BindCTestHelper1(Adjoint S, _);
AssertOperationsEqualReferenced(op, target, 4);
}
operation OperationPowTest () : Unit {
AssertOperationsEqualReferenced(ApplyToEach(OperationPow(H, 2), _), NoOp<Qubit[]>, 3);
AssertOperationsEqualReferenced(ApplyToEach(OperationPow(Z, 2), _), NoOp<Qubit[]>, 3);
AssertOperationsEqualReferenced(ApplyToEach(OperationPow(S, 4), _), NoOp<Qubit[]>, 3);
AssertOperationsEqualReferenced(ApplyToEach(OperationPow(T, 8), _), NoOp<Qubit[]>, 3);
}
operation ApplyToSubregisterTest () : Unit {
let bigOp = ApplyPauli([PauliI, PauliX, PauliY, PauliZ, PauliI], _);
let smallOp = ApplyPauli([PauliX, PauliY, PauliZ], _);
AssertOperationsEqualReferenced(ApplyToSubregister(smallOp, [1, 2, 3], _), bigOp, 5);
AssertOperationsEqualReferenced(RestrictToSubregister(smallOp, [1, 2, 3]), bigOp, 5);
AssertOperationsEqualReferenced(ApplyToSubregisterC(smallOp, [1, 2, 3], _), bigOp, 5);
AssertOperationsEqualReferenced(RestrictToSubregisterC(smallOp, [1, 2, 3]), bigOp, 5);
AssertOperationsEqualReferenced(ApplyToSubregisterA(smallOp, [1, 2, 3], _), bigOp, 5);
AssertOperationsEqualReferenced(RestrictToSubregisterA(smallOp, [1, 2, 3]), bigOp, 5);
AssertOperationsEqualReferenced(ApplyToSubregisterCA(smallOp, [1, 2, 3], _), bigOp, 5);
AssertOperationsEqualReferenced(RestrictToSubregisterCA(smallOp, [1, 2, 3]), bigOp, 5);
}
operation CControlledExpected (op : (Qubit => Unit : Adjoint, Controlled), target : Qubit[]) : Unit {
body (...) {
op(target[0]);
op(target[2]);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation CControlledActual (op : (Qubit => Unit), target : Qubit[]) : Unit {
ApplyToEach(CControlled(op), Zip([true, false, true], target));
}
operation CControlledActualC (op : (Qubit => Unit : Controlled), target : Qubit[]) : Unit {
body (...) {
ApplyToEachC(CControlledC(op), Zip([true, false, true], target));
}
controlled distribute;
}
operation CControlledActualA (op : (Qubit => Unit : Adjoint), target : Qubit[]) : Unit {
body (...) {
ApplyToEachA(CControlledA(op), Zip([true, false, true], target));
}
adjoint invert;
}
operation CControlledActualCA (op : (Qubit => Unit : Adjoint, Controlled), target : Qubit[]) : Unit {
body (...) {
ApplyToEachCA(CControlledCA(op), Zip([true, false, true], target));
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation CControlledTest () : Unit {
AssertOperationsEqualReferenced(CControlledActual(H, _), CControlledExpected(H, _), 3);
AssertOperationsEqualReferenced(CControlledActual(Z, _), CControlledExpected(Z, _), 3);
AssertOperationsEqualReferenced(CControlledActual(S, _), CControlledExpected(S, _), 3);
AssertOperationsEqualReferenced(CControlledActual(T, _), CControlledExpected(T, _), 3);
}
operation CControlledTestC () : Unit {
AssertOperationsEqualReferenced(CControlledActualC(H, _), CControlledExpected(H, _), 3);
AssertOperationsEqualReferenced(CControlledActualC(Z, _), CControlledExpected(Z, _), 3);
AssertOperationsEqualReferenced(CControlledActualC(S, _), CControlledExpected(S, _), 3);
AssertOperationsEqualReferenced(CControlledActualC(T, _), CControlledExpected(T, _), 3);
}
operation CControlledTestA () : Unit {
AssertOperationsEqualReferenced(CControlledActualA(H, _), CControlledExpected(H, _), 3);
AssertOperationsEqualReferenced(CControlledActualA(Z, _), CControlledExpected(Z, _), 3);
AssertOperationsEqualReferenced(CControlledActualA(S, _), CControlledExpected(S, _), 3);
AssertOperationsEqualReferenced(CControlledActualA(T, _), CControlledExpected(T, _), 3);
}
operation CControlledTestCA () : Unit {
AssertOperationsEqualReferenced(CControlledActualCA(H, _), CControlledExpected(H, _), 3);
AssertOperationsEqualReferenced(CControlledActualCA(Z, _), CControlledExpected(Z, _), 3);
AssertOperationsEqualReferenced(CControlledActualCA(S, _), CControlledExpected(S, _), 3);
AssertOperationsEqualReferenced(CControlledActualCA(T, _), CControlledExpected(T, _), 3);
}
}

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
operation ApplyCShorthandToRegister(cGate : ((Qubit, Qubit) => Unit), target : Qubit[]) : Unit {
cGate(target[0], target[1]);
}
operation ApplyControlledOpToRegister(op : (Qubit => Unit : Adjoint, Controlled), target : Qubit[]) : Unit {
body (...) {
Controlled op(Most(target), Tail(target));
}
adjoint auto;
}
operation CXTest() : Unit {
let actual = ApplyCShorthandToRegister(CX, _);
let expected = ApplyControlledOpToRegister(X, _);
AssertOperationsEqualReferenced(actual, expected, 2);
}
operation CYTest() : Unit {
let actual = ApplyCShorthandToRegister(CY, _);
let expected = ApplyControlledOpToRegister(Y, _);
AssertOperationsEqualReferenced(actual, expected, 2);
}
operation CZTest() : Unit {
let actual = ApplyCShorthandToRegister(CZ, _);
let expected = ApplyControlledOpToRegister(Z, _);
AssertOperationsEqualReferenced(actual, expected, 2);
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
function ResultAsIntTest () : Unit {
AssertIntEqual(ResultAsInt([Zero, Zero]), 0, $"Expected [Zero, Zero] to be represented by 0.");
AssertIntEqual(ResultAsInt([One, Zero]), 1, $"Expected [One, Zero] to be represented by 1.");
AssertIntEqual(ResultAsInt([Zero, One]), 2, $"Expected [Zero, One] to be represented by 2.");
AssertIntEqual(ResultAsInt([One, One]), 3, $"Expected [One, One] to be represented by 3.");
}
function BoolArrFromPositiveIntTest () : Unit {
for (number in 0 .. 100) {
let bits = BoolArrFromPositiveInt(number, 9);
let inte = PositiveIntFromBoolArr(bits);
AssertIntEqual(inte, number, $"Integer converted to bit string and back should be identical");
}
let bits70 = [false, true, true, false, false, false, true, false];
let number70 = PositiveIntFromBoolArr(bits70);
AssertIntEqual(70, number70, $"Integer from 01000110 in little Endian should be 70");
}
}

Просмотреть файл

@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
function IsEven (element : Int) : Bool {
return element % 2 == 0;
}
function IsSingleDigit (element : Int) : Bool {
return element >= 0 && element < 10;
}
function Add (input : (Int, Int)) : Int {
let (first, second) = input;
return first + second;
}
function Squarer (a : Int) : Int {
return a * a;
}
function ForAllTest () : Unit {
AssertBoolEqual(ForAll(IsSingleDigit, [3, 4, 7, 8]), true, $"the elements [3, 4, 7, 8] were not found to be single digit numbers.");
AssertBoolEqual(ForAll(IsSingleDigit, [3, 4, 7, 18]), false, $"the elements [3, 4, 7, 18] were found to be single digit numbers.");
}
function ForAnyTest () : Unit {
AssertBoolEqual(ForAny(IsEven, [3, 7, 99, -4]), true, $"the elements [3, 7, 99, -4] were not found to contain at least one even number.");
AssertBoolEqual(ForAny(IsEven, [3, 7, 99, -41]), false, $"the elements [3, 7, 99, -4] were not found to contain at least one even number.");
}
function FoldTest () : Unit {
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
AssertIntEqual(Fold(Add, 0, array), 55, $"folding the summation over [1..10] did not yield 55.");
}
function MapTest () : Unit {
let array = [1, 2, 3, 4];
let squaredArray = Map(Squarer, array);
AssertIntEqual(Fold(Add, 0, squaredArray), 30, $"the sum of the squares of [1, 2, 3, 4] was not found to be 30.");
}
function ExtremaTest () : Unit {
let array = [-10, 10, 7, 0];
AssertIntEqual(-10, Min(array), $"Min failed.");
AssertIntEqual(10, Max(array), $"Max failed.");
}
}

144
Canon/tests/MathTests.qs Normal file
Просмотреть файл

@ -0,0 +1,144 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
function NativeFnsAreCallableTest () : Unit {
let arg = PI() / 2.0;
AssertAlmostEqual(Sin(arg), 1.0);
AssertAlmostEqual(Cos(arg), 0.0);
let arcArg = 1.0;
AssertAlmostEqual(ArcCos(arcArg), 0.0);
AssertAlmostEqual(ArcSin(arcArg), arg);
}
function RealModTest () : Unit {
AssertAlmostEqual(RealMod(5.5 * PI(), 2.0 * PI(), 0.0), 1.5 * PI());
AssertAlmostEqual(RealMod(0.5 * PI(), 2.0 * PI(), -PI() / 2.0), 0.5 * PI());
}
function ArcHyperbolicFnsTest () : Unit {
// These tests were generated using NumPy's implementations
// of the inverse hyperbolic functions.
AssertAlmostEqual(ArcTanh(0.3), 0.30951960420311175);
AssertAlmostEqual(ArcCosh(1.3), 0.75643291085695963);
AssertAlmostEqual(ArcSinh(-0.7), -0.65266656608235574);
}
function ExtendedGCDTestHelper (a : Int, b : Int, gcd : Int) : Unit {
Message($"Testing {a}, {b}, {gcd} ");
let (u, v) = ExtendedGCD(a, b);
let expected = AbsI(gcd);
let actual = AbsI(u * a + v * b);
AssertIntEqual(expected, actual, $"Expected absolute value of gcd to be {expected}, got {actual}");
}
function ExtendedGCDTest () : Unit {
let testTuples = [(1, 1, 1), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), (5, 7, 1), (-5, 7, 1), (3, 15, 3)];
Ignore(Map(ExtendedGCDTestHelper, testTuples));
}
function BitSizeTest () : Unit {
AssertIntEqual(BitSize(3), 2, $"BitSize(3) must be 2");
AssertIntEqual(BitSize(7), 3, $"BitSize(7) must be 2");
}
function ExpModTest () : Unit {
// this test is generated using Mathematica PowerMod function
let result = ExpMod(5, 4611686018427387903, 7);
AssertIntEqual(result, 6, $"The result must be 6, got {result}");
}
function ContinuedFractionConvergentTestHelper (numerator : Int, denominator : Int) : Unit {
let bitSize = 2 * BitSize(denominator);
let numeratorDyadic = (numerator * 2 ^ bitSize) / denominator;
let (u, v) = (ContinuedFractionConvergent(Fraction(numeratorDyadic, 2 ^ bitSize), denominator))!;
AssertBoolEqual(AbsI(u) == numerator && AbsI(v) == denominator, true, $"The result must be ±{numerator}/±{denominator} got {u}/{v}");
}
function ContinuedFractionConvergentEdgeCaseTestHelper (numerator : Int, denominator : Int, bound : Int) : Unit {
let (num, denom) = (ContinuedFractionConvergent(Fraction(numerator, denominator), bound))!;
AssertBoolEqual(AbsI(num) == numerator && AbsI(denom) == denominator, true, $"The result must be ±{numerator}/±{denominator} got {num}/{denom}");
}
function ContinuedFractionConvergentTest () : Unit {
let testTuples = [(29, 47), (17, 37), (15, 67)];
Ignore(Map(ContinuedFractionConvergentTestHelper, testTuples));
let edgeCaseTestTuples = [(1, 4, 512), (3, 4, 512)];
Ignore(Map(ContinuedFractionConvergentEdgeCaseTestHelper, edgeCaseTestTuples));
}
function ComplexMathTest () : Unit {
mutable complexCases = [(0.123, 0.321), (0.123, -0.321), (-0.123, 0.321), (-0.123, -0.321)];
for (idxCases in 0 .. Length(complexCases) - 1) {
let (complexRe, complexIm) = complexCases[idxCases];
let complexAbs = Sqrt(complexRe * complexRe + complexIm * complexIm);
let complexArg = ArcTan2(complexIm, complexRe);
let complex = Complex(complexRe, complexIm);
let complexPolar = ComplexPolar(complexAbs, complexArg);
AssertAlmostEqual(AbsSquaredComplex(complex), complexAbs * complexAbs);
AssertAlmostEqual(AbsComplex(complex), complexAbs);
AssertAlmostEqual(ArgComplex(complex), complexArg);
AssertAlmostEqual(AbsSquaredComplexPolar(complexPolar), complexAbs * complexAbs);
AssertAlmostEqual(AbsComplexPolar(complexPolar), complexAbs);
AssertAlmostEqual(ArgComplexPolar(complexPolar), complexArg);
let (x, y) = (ComplexPolarToComplex(complexPolar))!;
AssertAlmostEqual(x, complexRe);
AssertAlmostEqual(y, complexIm);
let (r, t) = (ComplexToComplexPolar(complex))!;
AssertAlmostEqual(r, complexAbs);
AssertAlmostEqual(t, complexArg);
}
}
function PNormTest () : Unit {
mutable testCases = [
(1.0, [-0.1, 0.2, 0.3], 0.6),
(1.5, [0.1, -0.2, 0.3], 0.43346228721136096815),
(2.0, [0.1, 0.2, -0.3], 0.37416573867739413856),
(3.0, [0.0, 0.0, -0.0], 0.0)
];
for (idxTest in 0 .. Length(testCases) - 1) {
let (p, array, pNormExpected) = testCases[idxTest];
AssertAlmostEqual(PNorm(p, array), pNormExpected);
// if PNorm fails, PNormalize will fail.
let arrayNormalized = PNormalize(p, array);
for (idxCoeff in 0 .. Length(array) - 1) {
AssertAlmostEqual(array[idxCoeff] / pNormExpected, arrayNormalized[idxCoeff]);
}
}
}
}

Просмотреть файл

@ -0,0 +1,574 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Convert;
operation MultiplexZTestHelper (coefficients : Double[], multiplexerControl : BigEndian, additionalControl : Qubit[], target : Qubit, tolerance : Double) : Unit {
let nCoefficients = Length(coefficients);
let nQubits = (Length(multiplexerControl!) + Length(additionalControl)) + 1;
// Measure phase shift due to Exp^PauliZ rotation.
H(target);
// Generate uniform superposition over control inputs.
for (idxMultiplexer in 0 .. Length(multiplexerControl!) - 1) {
H(multiplexerControl![idxMultiplexer]);
}
for (idxAdditional in 0 .. Length(additionalControl) - 1) {
H(additionalControl[idxAdditional]);
}
// For deterministic test of particular number state `idx', we could use the following
//let bits = Reverse(BoolArrFromPositiveInt (idx, Length(multiplexerControl)));
//for(idxBits in 0..Length(bits)-1){
// if(bits[idxBits]){
// X(multiplexerControl[idxBits]);
// }
//}
// Apply MultiplexZ circuit
if (Length(additionalControl) == 0) {
MultiplexZ(coefficients, multiplexerControl, target);
}
elif (Length(additionalControl) == 1) {
Controlled (MultiplexZ(coefficients, multiplexerControl, _))(additionalControl, target);
}
else {
fail $"Test for more than one control on MultiplexZ not implemented.";
}
// Sample from control registers and check phase using AssertProb.
let multiplexerControlInteger = MeasureIntegerBE(multiplexerControl);
let additionalControlResults = MultiM(additionalControl);
if (Length(additionalControlResults) == 1 && additionalControlResults[0] == Zero) {
// Case where Identity operation is performed.
Message($"Controlled MultiplexZ test. coefficient {multiplexerControlInteger} of {nCoefficients-1}.");
AssertPhase(0.0, target, tolerance);
}
else {
mutable coeff = 0.0;
if (multiplexerControlInteger < nCoefficients) {
set coeff = coefficients[multiplexerControlInteger];
}
if (Length(additionalControl) == 0) {
Message($"MultiplexZ test. Qubits: {nQubits}; coefficient {multiplexerControlInteger} of {nCoefficients-1}.");
AssertPhase(coeff, target, tolerance);
}
else {
Message($"Controlled MultiplexZ test. Qubits: {nQubits}; coefficient {multiplexerControlInteger} of {nCoefficients-1}.");
AssertPhase(coeff, target, tolerance);
}
//AssertPhase(coeff, target, tolerance);
}
ResetAll(multiplexerControl!);
ResetAll(additionalControl);
Reset(target);
}
operation MultiplexZTest () : Unit {
let maxQubits = 6;
// Loop over controlled & un-controlled Multiplexer
for (nAdditionalControl in 0 .. 1) {
// Loop over number of Multiplexer qubits
for (nMultiplexerControl in 0 .. maxQubits - 2) {
//Loop over some number of missing coefficients
for (missingCoefficients in 0 .. nMultiplexerControl) {
// Generate some coefficients
let maxCoefficients = 2 ^ nMultiplexerControl;
let nCoefficients = maxCoefficients - missingCoefficients;
mutable coefficients = new Double[nCoefficients];
for (idx in 0 .. Length(coefficients) - 1) {
set coefficients[idx] = (1.0 * ToDouble(idx + 1)) * 0.2;
}
// Allocate qubits
using (qubits = Qubit[(nMultiplexerControl + 1) + nAdditionalControl]) {
let multiplexerControl = BigEndian(qubits[0 .. nMultiplexerControl - 1]);
let target = qubits[nMultiplexerControl];
mutable additionalControl = new Qubit[1];
if (nAdditionalControl == 0) {
set additionalControl = new Qubit[0];
}
elif (nAdditionalControl == 1) {
set additionalControl = [qubits[Length(qubits) - 1]];
}
let tolerance = 1E-09;
// Repeat test some number of times
for (idxCoeff in 0 .. maxCoefficients / 2) {
MultiplexZTestHelper(coefficients, multiplexerControl, additionalControl, target, tolerance);
}
}
}
}
}
}
operation ApplyDiagonalUnitaryTestHelper (coefficients : Double[], qubits : BigEndian, tolerance : Double) : Unit {
let nCoefficients = Length(coefficients);
let nQubits = Length(qubits!);
// The absolute phase of a diagonal unitary can only be characeterized
// using a controlled operation.
using (control = Qubit[1]) {
for (idxCoeff in 0 .. Length(coefficients) - 1) {
H(control[0]);
//for(idxQubit in 0..nQubits-1){
// H(qubits[idxQubit]);
//}
// For deterministic test of particular number state `idx', we could use the following
let bits = Reverse(BoolArrFromPositiveInt(idxCoeff, nQubits));
for (idxBits in 0 .. Length(bits) - 1) {
if (bits[idxBits]) {
X(qubits![idxBits]);
}
}
// Apply MultiplexZ circuit
Controlled (ApplyDiagonalUnitary(coefficients, _))(control, qubits);
Message($"ApplyDiagonalUnitary test. Qubits: {nQubits}; coefficient {idxCoeff} of {nCoefficients-1}.");
AssertPhase(-0.5 * coefficients[idxCoeff], control[0], tolerance);
ResetAll(control);
ResetAll(qubits!);
}
}
}
operation ApplyDiagonalUnitaryTest () : Unit {
let maxQubits = 4;
for (nqubits in 1 .. maxQubits) {
// Generate some coefficients
let maxCoefficients = 2 ^ nqubits;
//let nCoefficients = maxCoefficients - missingCoefficients;
mutable coefficients = new Double[maxCoefficients];
for (idx in 0 .. Length(coefficients) - 1) {
set coefficients[idx] = (1.0 * ToDouble(idx + 1)) * 0.3;
}
// Allocate qubits
using (qubits = Qubit[nqubits]) {
let tolerance = 1E-09;
ApplyDiagonalUnitaryTestHelper(coefficients, BigEndian(qubits), tolerance);
}
}
}
function MultiplexOperationsTestUnitary (nStates : Int, idx : Int) : (Qubit => Unit : Adjoint, Controlled)[] {
mutable unitaries = new (Qubit => Unit : Adjoint, Controlled)[nStates];
for (idxUnitary in 0 .. nStates - 1) {
set unitaries[idxUnitary] = I;
}
set unitaries[idx] = X;
return unitaries;
}
operation MultiplexOperationsTestHelper (idxTest : Int, idxTarget : Int, nQubits : Int, idxControl : Int, nControls : Int) : Result {
let unitaries = MultiplexOperationsTestUnitary(2 ^ nQubits, idxTarget);
// BigEndian
let bits = Reverse(BoolArrFromPositiveInt(idxTest, nQubits));
let controlBits = Reverse(BoolArrFromPositiveInt(idxControl, nControls));
mutable result = Zero;
if (nControls == 0) {
using (target = Qubit[1]) {
using (index = Qubit[nQubits]) {
for (idxBits in 0 .. Length(bits) - 1) {
if (bits[idxBits]) {
X(index[idxBits]);
}
}
MultiplexOperations(unitaries, BigEndian(index), target[0]);
set result = M(target[0]);
ResetAll(target);
ResetAll(index);
}
}
}
else {
using (control = Qubit[nControls]) {
using (target = Qubit[1]) {
if (nQubits == 0) {
let index = new Qubit[0];
for (idxControlBits in 0 .. Length(controlBits) - 1) {
if (controlBits[idxControlBits]) {
X(control[idxControlBits]);
}
}
Controlled (MultiplexOperations(unitaries, BigEndian(index), _))(control, target[0]);
set result = M(target[0]);
ResetAll(target);
ResetAll(control);
}
else {
using (index = Qubit[nQubits]) {
for (idxBits in 0 .. Length(bits) - 1) {
if (bits[idxBits]) {
X(index[idxBits]);
}
}
for (idxControlBits in 0 .. Length(controlBits) - 1) {
if (controlBits[idxControlBits]) {
X(control[idxControlBits]);
}
}
Controlled (MultiplexOperations(unitaries, BigEndian(index), _))(control, target[0]);
set result = M(target[0]);
ResetAll(target);
ResetAll(index);
ResetAll(control);
}
}
}
}
}
return result;
}
function MultiplexOperationsTestMissingUnitary (nStates : Int, nUnitaries : Int) : (Qubit => Unit : Adjoint, Controlled)[] {
mutable unitaries = new (Qubit => Unit : Adjoint, Controlled)[nStates];
for (idxUnitary in 0 .. nUnitaries - 1) {
set unitaries[idxUnitary] = X;
}
for (idxUnitary in nUnitaries .. nStates - 1) {
set unitaries[idxUnitary] = I;
}
return unitaries;
}
operation MultiplexOperationsTestMissingUnitaryHelper (idxTest : Int, nUnitaries : Int, nQubits : Int) : Result {
let unitaries = MultiplexOperationsTestMissingUnitary(2 ^ nQubits, nUnitaries);
// BigEndian
let bits = Reverse(BoolArrFromPositiveInt(idxTest, nQubits));
mutable result = Zero;
using (target = Qubit[1]) {
if (nQubits == 0) {
let index = new Qubit[0];
for (idxBits in 0 .. Length(bits) - 1) {
if (bits[idxBits]) {
X(index[idxBits]);
}
}
MultiplexOperations(unitaries, BigEndian(index), target[0]);
set result = M(target[0]);
ResetAll(target);
}
else {
using (index = Qubit[nQubits]) {
for (idxBits in 0 .. Length(bits) - 1) {
if (bits[idxBits]) {
X(index[idxBits]);
}
}
MultiplexOperations(unitaries, BigEndian(index), target[0]);
set result = M(target[0]);
ResetAll(target);
ResetAll(index);
}
}
}
return result;
}
operation MultiplexOperationsTest () : Unit {
mutable result = Zero;
// Test version with fewer unitaries than states
// Test uncontrolled version
for (missingTestQubits in 1 .. 3) {
for (nUnitaries in 0 .. 2 ^ missingTestQubits) {
for (idxTest in 0 .. 2 ^ missingTestQubits - 1) {
set result = MultiplexOperationsTestMissingUnitaryHelper(idxTest, nUnitaries, missingTestQubits);
if (result == One) {
Message($"MultiplexOperations test with missing unitaries. Qubits: {missingTestQubits}; idxTest {idxTest} of nUnitaries {nUnitaries} result {result}.");
if (idxTest >= nUnitaries) {
fail $"MultiplexOperations failed.";
}
}
if (result == Zero) {
Message($"MultiplexOperations test with missing unitaries. Qubits: {missingTestQubits}; idxTest {idxTest} of nUnitaries {nUnitaries} result {result}.");
if (idxTest < nUnitaries) {
fail $"MultiplexOperations failed.";
}
}
}
}
}
let nQubits = 3;
let nIdxMax = 2 ^ nQubits;
// Test uncontrolled version
for (idxTarget in 0 .. nIdxMax - 1) {
for (idxTest in 0 .. nIdxMax - 1) {
set result = MultiplexOperationsTestHelper(idxTest, idxTarget, nQubits, 0, 0);
if (result == One) {
Message($"MultiplexOperations test. Qubits: {nQubits}; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, $"MultiplexOperations failed.");
}
}
}
// Test Controlled version
for (idxTarget in 0 .. nIdxMax - 1) {
for (idxTest in 0 .. nIdxMax - 1) {
set result = MultiplexOperationsTestHelper(idxTest, idxTarget, nQubits, 0, 1);
if (result == One) {
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 0; nControls = 1; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, $"MultiplexOperations failed.");
}
set result = MultiplexOperationsTestHelper(idxTest, idxTarget, nQubits, 1, 1);
if (result == One) {
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 1; nControls = 1; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, $"MultiplexOperations failed.");
}
set result = MultiplexOperationsTestHelper(idxTest, idxTarget, nQubits, 1, 2);
if (result == One) {
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 1; nControls = 2; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, $"MultiplexOperations failed.");
}
set result = MultiplexOperationsTestHelper(idxTest, idxTarget, nQubits, 3, 2);
if (result == One) {
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 3; nControls = 2; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, $"MultiplexOperations failed.");
}
}
}
}
function MultiplexOperationsFromGeneratorTestUnitary_(nStates: Int, idx: Int, idxX: Int) : (Qubit[] => Unit : Adjoint, Controlled) {
if(idx == idxX ){
return ApplyToEachCA(X,_);
}
elif(idx < nStates){
return ApplyToEachCA(I,_);
}
else{
fail "Index out of range";
}
}
function MultiplexOperationsFromGeneratorTestUnitary(nStates: Int, idx: Int) : (Int, (Int -> (Qubit[] => Unit : Adjoint, Controlled))) {
return (nStates, MultiplexOperationsFromGeneratorTestUnitary_(nStates, _, idx));
}
operation MultiplexOperationsFromGeneratorTestHelper(idxTest: Int, idxTarget: Int, nQubits: Int, idxControl: Int, nControls: Int) : Result {
body (...) {
let unitaries = MultiplexOperationsFromGeneratorTestUnitary(2^nQubits, idxTarget);
// BigEndian
let bits = Reverse(BoolArrFromPositiveInt (idxTest, nQubits));
let controlBits = Reverse(BoolArrFromPositiveInt (idxControl, nControls));
mutable result = Zero;
if(nControls == 0){
using(target = Qubit[1]){
using(index = Qubit[nQubits]){
for(idxBits in 0..Length(bits)-1){
if(bits[idxBits]){
X(index[idxBits]);
}
}
MultiplexOperationsFromGenerator(unitaries, BigEndian(index), [target[0]]);
set result = M(target[0]);
ResetAll(target);
ResetAll(index);
}
}
}
else{
using(control = Qubit[nControls]){
using(target = Qubit[1]){
if(nQubits == 0){
let index = new Qubit[0];
for(idxControlBits in 0..Length(controlBits)-1){
if(controlBits[idxControlBits]){
X(control[idxControlBits]);
}
}
Controlled (MultiplexOperationsFromGenerator(unitaries, BigEndian(index), _))(control, [target[0]]);
set result = M(target[0]);
ResetAll(target);
ResetAll(control);
}
else{
using(index = Qubit[nQubits]){
for(idxBits in 0..Length(bits)-1){
if(bits[idxBits]){
X(index[idxBits]);
}
}
for(idxControlBits in 0..Length(controlBits)-1){
if(controlBits[idxControlBits]){
X(control[idxControlBits]);
}
}
Controlled (MultiplexOperationsFromGenerator(unitaries, BigEndian(index), _))(control, [target[0]]);
set result = M(target[0]);
ResetAll(target);
ResetAll(index);
ResetAll(control);
}
}
}
}
}
return result;
}
}
operation MultiplexOperationsFromGeneratorTest() : Unit{
body (...) {
mutable result = Zero;
let nQubits = 3;
let nIdxMax = 2^nQubits;
// Test uncontrolled version
for(idxTarget in 0..nIdxMax-1){
for(idxTest in 0..nIdxMax-1){
set result = MultiplexOperationsFromGeneratorTestHelper(idxTest, idxTarget, nQubits, 0, 0);
if(result == One){
Message($"MultiplexOperations test. Qubits: {nQubits}; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, "MultiplexOperations failed.");
}
}
}
// Test Controlled version
for(idxTarget in 0..nIdxMax-1){
for(idxTest in 0..nIdxMax-1){
set result = MultiplexOperationsFromGeneratorTestHelper(idxTest, idxTarget, nQubits, 0, 1);
if(result == One){
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 0; nControls = 1; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, "MultiplexOperations failed.");
}
set result = MultiplexOperationsFromGeneratorTestHelper(idxTest, idxTarget, nQubits, 1, 1);
if(result == One){
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 1; nControls = 1; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, "MultiplexOperations failed.");
}
set result = MultiplexOperationsFromGeneratorTestHelper(idxTest, idxTarget, nQubits, 1, 2);
if(result == One){
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 1; nControls = 2; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, "MultiplexOperations failed.");
}
set result = MultiplexOperationsFromGeneratorTestHelper(idxTest, idxTarget, nQubits, 3, 2);
if(result == One){
Message($"Controlled MultiplexOperations test. Qubits: {nQubits}; idxControl = 3; nControls = 2; idxTest {idxTest} of idxTarget {idxTarget} result {result}.");
AssertIntEqual(idxTarget, idxTest, "MultiplexOperations failed.");
}
}
}
}
}
}

Просмотреть файл

@ -1,19 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Canon;
function PairTest() : () {
function PairTest () : Unit {
let pair = (12, PauliZ);
if (Fst(pair) != 12) {
let actual = Fst(pair);
fail $"Expected 12, actual {actual}.";
}
if (Snd(pair) != PauliZ) {
let actual = Snd(pair);
fail $"Expected PauliZ, actual {actual}.";
}
}
}

41
Canon/tests/PauliTests.qs Normal file
Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
operation MeasureWithScratchTest () : Unit {
using (register = Qubit[2]) {
PrepareEntangledState([register[0]], [register[1]]);
X(register[1]);
let xxScratch = MeasureWithScratch([PauliX, PauliX], register);
let xx = Measure([PauliX, PauliX], register);
if (xx != xxScratch) {
fail $"〈XX〉: MeasureWithScratch and Measure disagree";
}
let yyScratch = MeasureWithScratch([PauliY, PauliY], register);
let yy = Measure([PauliY, PauliY], register);
if (yy != yyScratch) {
fail $"〈yy〉: MeasureWithScratch and Measure disagree";
}
let zzScratch = MeasureWithScratch([PauliZ, PauliZ], register);
let zz = Measure([PauliZ, PauliZ], register);
if (zz != zzScratch) {
fail $"〈ZZ〉: MeasureWithScratch and Measure disagree";
}
ResetAll(register);
}
}
}

112
Canon/tests/QFTTests.qs Normal file
Просмотреть файл

@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// To test QFT we hard code circuits based on Figure 5.1 on Page 219 of
// [ *Michael A. Nielsen , Isaac L. Chuang*,
// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667)
/// # Summary
/// Hard-code 1 qubit QFT
operation QFT1 (target : BigEndian) : Unit {
body (...) {
AssertIntEqual(Length(target!), 1, $"`Length(target!)` must be 1");
H((target!)[0]);
}
adjoint invert;
}
/// # Summary
/// Hard-code 2 qubit QFT
operation QFT2 (target : BigEndian) : Unit {
body (...) {
AssertIntEqual(Length(target!), 2, $"`Length(target!)` must be 2");
let (q1, q2) = ((target!)[0], (target!)[1]);
H(q1);
Controlled R1Frac([q2], (2, 2, q1));
H(q2);
SWAP(q1, q2);
}
adjoint invert;
}
/// # Summary
/// Hard-code 3 qubit QFT
operation QFT3 (target : BigEndian) : Unit {
body (...) {
AssertIntEqual(Length(target!), 3, $"`Length(target)` must be 3");
let (q1, q2, q3) = ((target!)[0], (target!)[1], (target!)[2]);
H(q1);
Controlled R1Frac([q2], (2, 2, q1));
Controlled R1Frac([q3], (2, 3, q1));
H(q2);
Controlled R1Frac([q3], (2, 2, q2));
H(q3);
SWAP(q1, q3);
}
adjoint invert;
}
/// # Summary
/// Hard-code 4 qubit QFT
operation QFT4 (target : BigEndian) : Unit {
body (...) {
AssertIntEqual(Length(target!), 4, $"`Length(target!)` must be 4");
let (q1, q2, q3, q4) = ((target!)[0], (target!)[1], (target!)[2], (target!)[3]);
H(q1);
Controlled R1Frac([q2], (2, 2, q1));
Controlled R1Frac([q3], (2, 3, q1));
Controlled R1Frac([q4], (2, 4, q1));
H(q2);
Controlled R1Frac([q3], (2, 2, q2));
Controlled R1Frac([q4], (2, 3, q2));
H(q3);
Controlled R1Frac([q4], (2, 2, q3));
H(q4);
SWAP(q1, q4);
SWAP(q2, q3);
}
adjoint invert;
}
operation ApplyBEToRegisterA (op : (BigEndian => Unit : Adjoint), target : Qubit[]) : Unit {
body (...) {
op(BigEndian(target));
}
adjoint invert;
}
/// # Summary
/// Compares QFT to the hard-coded implementations
operation QFTTest () : Unit {
let testFunctions = [QFT1, QFT2, QFT3, QFT4];
for (i in 0 .. Length(testFunctions) - 1) {
AssertOperationsEqualReferenced(ApplyBEToRegisterA(testFunctions[i], _), ApplyBEToRegisterA(QFT, _), i + 1);
}
}
}

102
Canon/tests/QcvvTests.qs Normal file
Просмотреть файл

@ -0,0 +1,102 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
operation ChoiStateTest () : Unit {
using (register = Qubit[2]) {
PrepareChoiStateCA(NoOp<Qubit[]>, [register[0]], [register[1]]);
// As usual, the same confusion about {+1, -1} and {0, 1}
// labeling bites us here.
Assert([PauliX, PauliX], register, Zero, $"XX");
Assert([PauliZ, PauliZ], register, Zero, $"ZZ");
ResetAll(register);
}
}
operation EstimateFrequencyTest () : Unit {
let freq = EstimateFrequency(ApplyToEach(H, _), MeasureAllZ, 1, 1000);
AssertAlmostEqualTol(freq, 0.5, 0.1);
}
operation _RobustPhaseEstimationTestOp (phase : Double, power : Int, qubits : Qubit[]) : Unit {
body (...) {
//Rz(- 2.0* phase * ToDouble(power), qubits[0])
Exp([PauliZ], phase * ToDouble(power), qubits);
//Exp([PauliI], phase * ToDouble(power), qubits);
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation RobustPhaseEstimationDemoImpl (phaseSet : Double, bitsPrecision : Int) : Double {
let op = DiscreteOracle(_RobustPhaseEstimationTestOp(phaseSet, _, _));
mutable phaseEst = ToDouble(0);
using (q = Qubit[1]) {
set phaseEst = RobustPhaseEstimation(bitsPrecision, op, q);
ResetAll(q);
}
return phaseEst;
}
// Probabilistic test. Might fail occasionally
operation RobustPhaseEstimationTest () : Unit {
let bitsPrecision = 10;
for (idxTest in 0 .. 9) {
let phaseSet = ((2.0 * PI()) * ToDouble(idxTest - 5)) / 12.0;
let phaseEst = RobustPhaseEstimationDemoImpl(phaseSet, bitsPrecision);
AssertAlmostEqualTol(phaseEst, phaseSet, 0.01);
}
}
operation PrepareQubitTest () : Unit {
using (register = Qubit[1]) {
let qubit = register[0];
let bases = [PauliI, PauliX, PauliY, PauliZ];
for (idxBasis in 0 .. Length(bases) - 1) {
let basis = bases[idxBasis];
PrepareQubit(basis, qubit);
Assert([basis], register, Zero, $"Did not prepare in {basis} correctly.");
Reset(qubit);
}
}
}
operation SingleQubitProcessTomographyMeasurementTest () : Unit {
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliI, PauliI, H), Zero, $"Failed at ⟪I | H | I⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliX, PauliI, H), Zero, $"Failed at ⟪I | H | X⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliY, PauliI, H), Zero, $"Failed at ⟪I | H | Y⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliZ, PauliI, H), Zero, $"Failed at ⟪I | H | Z⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliX, PauliZ, H), Zero, $"Failed at ⟪Z | H | X⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliY, PauliY, H), One, $"Failed at -⟪Y | H | Y⟫.");
AssertResultEqual(SingleQubitProcessTomographyMeasurement(PauliX, PauliZ, H), Zero, $"Failed at ⟪Z | H | X⟫.");
}
}

461
Canon/tests/QeccTests.qs Normal file
Просмотреть файл

@ -0,0 +1,461 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// NB: These tests need to be generalized to allow for unit testing CSS
// codes as well. Since the recovery functions look different for CSS
// codes, we must test the Steane code more manually.
operation QeccTestCaseImpl (code : QECC, nScratch : Int, fn : RecoveryFn, error : (Qubit[] => Unit), data : Qubit[]) : Unit {
let (encode, decode, syndMeas) = code!;
using (scratch = Qubit[nScratch]) {
let logicalRegister = encode!(data, scratch);
// Cause an error.
error(logicalRegister!);
Recover(code, fn, logicalRegister);
let (decodedData, decodedScratch) = decode!(logicalRegister);
ApplyToEach(Reset, decodedScratch);
}
}
function QeccTestCase (code : QECC, nScratch : Int, fn : RecoveryFn, error : (Qubit[] => Unit)) : (Qubit[] => Unit) {
return QeccTestCaseImpl(code, nScratch, fn, error, _);
}
operation AssertCodeCorrectsErrorImpl (code : QECC, nLogical : Int, nScratch : Int, fn : RecoveryFn, error : (Qubit[] => Unit)) : Unit {
AssertOperationsEqualReferenced(QeccTestCase(code, nScratch, fn, error), NoOp<Qubit[]>, nLogical);
}
/// # Remarks
/// This is a function which curries over all but the error to be applied,
/// and does not explicitly refer to qubits in any way.
/// Thus, the result of evaluating this function is an operation that can
/// be passed to ApplyToEach<(Qubit[] => ())> in order to test a *collection* of
/// errors in a compact way.
function AssertCodeCorrectsError (code : QECC, nLogical : Int, nScratch : Int, fn : RecoveryFn) : ((Qubit[] => Unit) => Unit) {
return AssertCodeCorrectsErrorImpl(code, nLogical, nScratch, fn, _);
}
/// # Summary
/// Ensures that the bit flip code can correct a single arbitrary
/// bit-flip ($X$) error.
operation BitFlipTest () : Unit {
let code = BitFlipCode();
let fn = BitFlipRecoveryFn();
let errors = Map(CurryOp(ApplyPauli), [[PauliX, PauliI, PauliI], [PauliI, PauliX, PauliI], [PauliI, PauliI, PauliX]]);
let assertionGenerator = AssertCodeCorrectsError(code, 1, 2, fn);
assertionGenerator(NoOp<Qubit[]>);
ApplyToEach(assertionGenerator, errors);
}
/// # Summary
/// Ensures that the 5-qubit perfect code can correct an arbitrary
/// single-qubit error.
operation FiveQubitCodeTest () : Unit {
let code = FiveQubitCode();
let fn = FiveQubitCodeRecoveryFn();
let assertionGenerator = AssertCodeCorrectsError(code, 1, 4, fn);
let errors = Map(CurryOp(ApplyPauli), WeightOnePaulis(5));
assertionGenerator(NoOp<Qubit[]>);
ApplyToEach(assertionGenerator, errors);
}
// TODO: split this test up into several smaller tests.
operation FiveQubitTediousTest () : Unit {
let s = SyndromeMeasOp(MeasureStabilizerGenerators([[PauliX, PauliZ, PauliZ, PauliX, PauliI], [PauliI, PauliX, PauliZ, PauliZ, PauliX], [PauliX, PauliI, PauliX, PauliZ, PauliZ], [PauliZ, PauliX, PauliI, PauliX, PauliZ]], _, MeasureWithScratch));
using (anc = Qubit[6]) {
Ry(PI() / 2.5, anc[0]);
FiveQubitCodeEncoderImpl([anc[0]], anc[1 .. 4]);
let m = anc[5];
mutable n = 0;
H(m);
Controlled X([m], anc[0]);
Controlled Z([m], anc[1]);
Controlled Z([m], anc[2]);
Controlled X([m], anc[3]);
H(m);
AssertQubit(Zero, m);
if (M(m) == One) {
set n = n + 1;
X(m);
}
H(m);
Controlled X([m], anc[1]);
Controlled Z([m], anc[2]);
Controlled Z([m], anc[3]);
Controlled X([m], anc[4]);
H(m);
if (M(m) == One) {
set n = n + 2;
X(m);
}
H(m);
Controlled X([m], anc[2]);
Controlled Z([m], anc[3]);
Controlled Z([m], anc[4]);
Controlled X([m], anc[0]);
H(m);
if (M(m) == One) {
set n = n + 4;
X(m);
}
H(m);
Controlled X([m], anc[3]);
Controlled Z([m], anc[4]);
Controlled Z([m], anc[0]);
Controlled X([m], anc[1]);
H(m);
if (M(m) == One) {
set n = n + 8;
X(m);
}
AssertIntEqual(n, 0, $"syndrome failure");
// Now testing MeasureWithScratch
if (MeasureWithScratch([PauliX, PauliZ, PauliZ, PauliX, PauliI], anc[0 .. 4]) == One) {
fail $"stabilizer 1 fail";
}
if (MeasureWithScratch([PauliI, PauliX, PauliZ, PauliZ, PauliX], anc[0 .. 4]) == One) {
fail $"stabilizer 2 fail";
}
if (MeasureWithScratch([PauliX, PauliI, PauliX, PauliZ, PauliZ], anc[0 .. 4]) == One) {
fail $"stabilizer 3 fail";
}
if (MeasureWithScratch([PauliZ, PauliX, PauliI, PauliX, PauliZ], anc[0 .. 4]) == One) {
fail $"stabilizer 4 fail";
}
ResetAll(anc);
}
}
operation FiveQubitTest () : Unit {
let s = SyndromeMeasOp(MeasureStabilizerGenerators([[PauliX, PauliZ, PauliZ, PauliX, PauliI], [PauliI, PauliX, PauliZ, PauliZ, PauliX], [PauliX, PauliI, PauliX, PauliZ, PauliZ], [PauliZ, PauliX, PauliI, PauliX, PauliZ]], _, MeasureWithScratch));
// TODO: split this test up into several smaller tests.
using (anc = Qubit[5]) {
// let's start with an arbitrary logical state.
Ry(PI() / 2.5, anc[0]);
FiveQubitCodeEncoderImpl([anc[0]], anc[1 .. 4]);
let syn = s!(LogicalRegister(anc));
let a = ResultAsInt(syn!);
AssertIntEqual(a, 0, $"syndrome failure");
let (encode, decode, syndMeas) = (FiveQubitCode())!;
let recovery = FiveQubitCodeRecoveryFn();
for (idx in 0 .. 4) {
X(anc[idx]);
let syndrome = syndMeas!(LogicalRegister(anc));
let recoveryOp = recovery!(syndrome);
ApplyPauli(recoveryOp, anc);
let ans = ResultAsInt((syndMeas!(LogicalRegister(anc)))!);
AssertIntEqual(ans, 0, $"Correction failure");
}
for (idx in 0 .. 4) {
Y(anc[idx]);
let syndrome = syndMeas!(LogicalRegister(anc));
let recoveryOp = recovery!(syndrome);
ApplyPauli(recoveryOp, anc);
let ans = ResultAsInt((syndMeas!(LogicalRegister(anc)))!);
AssertIntEqual(ans, 0, $"Correction failure");
}
for (idx in 0 .. 4) {
Z(anc[idx]);
let syndrome = syndMeas!(LogicalRegister(anc));
let recoveryOp = recovery!(syndrome);
ApplyPauli(recoveryOp, anc);
let ans = ResultAsInt((syndMeas!(LogicalRegister(anc)))!);
AssertIntEqual(ans, 0, $"Correction failure");
}
ResetAll(anc);
}
}
operation SteaneCodeEncoderTest () : Unit {
using (aux = Qubit[7]) {
SteaneCodeEncoderImpl(aux[0 .. 0], aux[1 .. 6]);
if (MeasureWithScratch([PauliX, PauliI, PauliX, PauliI, PauliX, PauliI, PauliX], aux[0 .. 6]) == One) {
fail $"Steane code first X stabilizer";
}
if (MeasureWithScratch([PauliI, PauliX, PauliX, PauliI, PauliI, PauliX, PauliX], aux[0 .. 6]) == One) {
fail $"Steane code second X stabilizer";
}
if (MeasureWithScratch([PauliI, PauliI, PauliI, PauliX, PauliX, PauliX, PauliX], aux[0 .. 6]) == One) {
fail $"Steane code third X stabilizer";
}
if (MeasureWithScratch([PauliZ, PauliI, PauliZ, PauliI, PauliZ, PauliI, PauliZ], aux[0 .. 6]) == One) {
fail $"Steane code first Z stabilizer";
}
if (MeasureWithScratch([PauliI, PauliZ, PauliZ, PauliI, PauliI, PauliZ, PauliZ], aux[0 .. 6]) == One) {
fail $"Steane code second Z stabilizer";
}
if (MeasureWithScratch([PauliI, PauliI, PauliI, PauliZ, PauliZ, PauliZ, PauliZ], aux[0 .. 6]) == One) {
fail $"Steane code third Z stabilizer";
}
ResetAll(aux);
}
}
operation Pi4YInjectionTest () : Unit {
using (anc = Qubit[2]) {
// magic state in anc[1]
Ry(PI() / 4.0, anc[1]);
let expected = ApplyToEachA(Ry(PI() / 4.0, _), _);
let actual = ApplyToEach(InjectPi4YRotation(_, anc[1]), _);
AssertOperationsEqualReferenced(actual, expected, 1);
// NB: we explicitly do not reset the
// qubit containing the magic state,
// so as to test whether the injection
// correctly reset for us.
Assert([PauliZ], [anc[1]], Zero, $"Magic state was not reset to |0〉.");
Reset(anc[0]);
}
}
operation Pi4YInjectionAdjointTest () : Unit {
using (anc = Qubit[2]) {
// magic state in anc[1]
Ry(PI() / 4.0, anc[1]);
let expected = ApplyToEachA(Ry(-PI() / 4.0, _), _);
let actual = ApplyToEach(Adjoint InjectPi4YRotation(_, anc[1]), _);
AssertOperationsEqualReferenced(actual, expected, 1);
// NB: we explicitly do not reset the
// qubit containing the magic state,
// so as to test whether the injection
// correctly reset for us.
Assert([PauliZ], [anc[1]], Zero, $"Magic state was not reset to |0〉.");
Reset(anc[0]);
}
}
/// # Summary
/// Applies logical operators before and after the encoding circuit,
/// that as a whole acts as identity.
operation KDLogicalOperatorTest () : Unit {
using (anc = Qubit[7]) {
X(anc[0]);
SteaneCodeEncoderImpl(anc[0 .. 0], anc[1 .. 6]);
// The logical qubit here is in One
X(anc[0]);
X(anc[1]);
X(anc[2]);
// The logical qubit here is in Zero
Z(anc[1]);
Z(anc[3]);
Z(anc[5]);
// Z logical operator does nothing.
let (logicalQubit, xsyn, zsyn) = _ExtractLogicalQubitFromSteaneCode(LogicalRegister(anc));
// The logical qubit must be in Zero
AssertIntEqual(xsyn, -1, $"X syndrome detected!");
AssertIntEqual(zsyn, -1, $"Z syndrome detected!");
AssertQubit(Zero, anc[0]);
ResetAll(anc);
}
}
operation KDSyndromeTest () : Unit {
using (anc = Qubit[7]) {
for (idx in 0 .. 6) {
ResetAll(anc);
SteaneCodeEncoderImpl(anc[0 .. 0], anc[1 .. 6]);
Z(anc[idx]);
let (logiQ, xsyn, zsyn) = _ExtractLogicalQubitFromSteaneCode(LogicalRegister(anc));
AssertIntEqual(idx, xsyn, $"wrong X syndrome");
ResetAll(anc);
SteaneCodeEncoderImpl(anc[0 .. 0], anc[1 .. 6]);
X(anc[idx]);
let (logiQ2, xsyn2, zsyn2) = _ExtractLogicalQubitFromSteaneCode(LogicalRegister(anc));
AssertIntEqual(idx, zsyn2, $"wrong Z syndrome");
}
ResetAll(anc);
}
}
operation KnillDistillationNoErrorTest () : Unit {
using (register = Qubit[15]) {
// Prepare the perfect magic states.
ApplyToEach(Ry(PI() / 4.0, _), register);
let accept = KnillDistill(register);
Ry(-PI() / 4.0, register[0]);
AssertBoolEqual(true, accept, $"Distillation failure");
ApplyToEach(AssertQubit(Zero, _), register);
// NB: no need to reset, we just asserted everything
// was returned to |0〉.
}
}
/// # Summary
/// Tests if the distillation routine works as intended.
/// This protocol is supposed to catch any weight 2 errors
/// on the input magic states, assuming perfect Cliffords.
/// Here we do not attempt to correct detected errors,
/// since corrections would make the output magic state
/// less accurate, compared to post-selection on zero syndrome.
operation KDTest () : Unit {
using (rm = Qubit[15]) {
ApplyToEach(Ry(PI() / 4.0, _), rm);
let acc = KnillDistill(rm);
// Check that the rough magic states were
// successfully reset to |0〉.
ApplyToEach(AssertQubit(Zero, _), Rest(rm));
Ry(-PI() / 4.0, rm[0]);
AssertBoolEqual(true, acc, $"Distillation failure");
AssertQubit(Zero, rm[0]);
// Cases where a single magic state is wrong
for (idx in 0 .. 14) {
ResetAll(rm);
ApplyToEach(Ry(PI() / 4.0, _), rm);
Y(rm[idx]);
let acc1 = KnillDistill(rm);
// Check that the rough magic states were
// successfully reset to |0〉.
ApplyToEach(AssertQubit(Zero, _), Rest(rm));
AssertBoolEqual(false, acc1, $"Distillation missed an error");
}
// Cases where two magic states are wrong
for (idxFirst in 0 .. 13) {
for (idxSecond in idxFirst + 1 .. 14) {
ResetAll(rm);
ApplyToEach(Ry(PI() / 4.0, _), rm);
Y(rm[idxFirst]);
Y(rm[idxSecond]);
let acc1 = KnillDistill(rm);
// Check that the rough magic states were
// successfully reset to |0〉.
ApplyToEach(AssertQubit(Zero, _), Rest(rm));
AssertBoolEqual(false, acc1, $"Distillation missed a pair error");
}
}
ResetAll(rm);
}
}
operation CSSTestCaseImpl (code : CSS, nScratch : Int, fnX : RecoveryFn, fnZ : RecoveryFn, error : (Qubit[] => Unit), data : Qubit[]) : Unit {
let (encode, decode, syndMeasX, syndMeasZ) = code!;
using (scratch = Qubit[nScratch]) {
let logicalRegister = encode!(data, scratch);
// Cause an error.
Message($"Applying error {error}.");
error(logicalRegister!);
RecoverCSS(code, fnX, fnZ, logicalRegister);
let (decodedData, decodedScratch) = decode!(logicalRegister);
ApplyToEach(Reset, decodedScratch);
}
}
function CSSTestCase (code : CSS, nScratch : Int, fnX : RecoveryFn, fnZ : RecoveryFn, error : (Qubit[] => Unit)) : (Qubit[] => Unit) {
return CSSTestCaseImpl(code, nScratch, fnX, fnZ, error, _);
}
operation AssertCSSCodeCorrectsErrorImpl (code : CSS, nLogical : Int, nScratch : Int, fnX : RecoveryFn, fnZ : RecoveryFn, error : (Qubit[] => Unit)) : Unit {
AssertOperationsEqualReferenced(CSSTestCase(code, nScratch, fnX, fnZ, error), NoOp<Qubit[]>, nLogical);
}
function AssertCSSCodeCorrectsError (code : CSS, nLogical : Int, nScratch : Int, fnX : RecoveryFn, fnZ : RecoveryFn) : ((Qubit[] => Unit) => Unit) {
return AssertCSSCodeCorrectsErrorImpl(code, nLogical, nScratch, fnX, fnZ, _);
}
/// # Summary
/// Ensures that the 7-qubit Steane code can correct an arbitrary
/// single-qubit error.
operation SteaneCodeTest () : Unit {
let code = SteaneCode();
let (fnX, fnZ) = SteaneCodeRecoveryFns();
let assertionGenerator = AssertCSSCodeCorrectsError(code, 1, 6, fnX, fnZ);
let errors = Map(CurryOp(ApplyPauli), WeightOnePaulis(7));
assertionGenerator(NoOp<Qubit[]>);
ApplyToEach(assertionGenerator, errors);
}
}

Просмотреть файл

@ -0,0 +1,58 @@
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Testing;
open Microsoft.Quantum.Extensions.Math;
/// # Summary
/// Assert that the QuantumPhaseEstimation operation for the T gate
/// return 0000 in the controlRegister when targetState is 0 and
/// return 0010 when the targetState is 1
operation QuantumPhaseEstimationTest () : Unit {
let oracle = DiscreteOracle(_TPhaseEstimation);
using (qPhase = Qubit[5]) {
let phase = BigEndian(qPhase[0 .. 3]);
let state = qPhase[4];
QuantumPhaseEstimation(oracle, [state], phase);
let complexOne = Complex(1.0, 0.0);
let complexZero = Complex(0.0, 0.0);
for (idxPhase in 0 .. 4) {
AssertQubitState((complexOne, complexZero), qPhase[idxPhase], 1E-06);
}
X(state);
QuantumPhaseEstimation(oracle, [state], phase);
AssertQubitState((complexOne, complexZero), qPhase[0], 1E-06);
AssertQubitState((complexOne, complexZero), qPhase[1], 1E-06);
AssertQubitState((complexZero, complexOne), qPhase[2], 1E-06);
AssertQubitState((complexOne, complexZero), qPhase[3], 1E-06);
AssertQubitState((complexZero, complexOne), qPhase[4], 1E-06);
ResetAll(qPhase);
}
}
/// # Summary
/// Implementation of T-gate for Quantum Phase Estimation Oracle
operation _TPhaseEstimation (power : Int, target : Qubit[]) : Unit {
body (...) {
for (idxPower in 0 .. power - 1) {
T(target[0]);
}
}
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
}

Просмотреть файл

@ -0,0 +1,105 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
// Tests the discretization algorithm
operation QuantumROMDiscretization_Test() : Unit {
for(rep in 0..20){
let coeffs = RandomInt(5000)+2;
let bitsPrecision = RandomInt(30)+1;
let barHeight = 2^(bitsPrecision) - 1;
mutable coefficients = new Double[coeffs];
Message($"Test case coeffs {coeffs}, bitsPrecision {bitsPrecision}");
for (idx in 0..coeffs-1)
{
set coefficients[idx] = 1000.0 * RandomReal(2*bitsPrecision);
}
// This avoids the case where coefficient are all zeros.
let rnd = RandomInt(coeffs);
set coefficients[rnd] = coefficients[rnd] + 1.0;
let (oneNorm, keepCoeff, altIndex) = QuantumROMDiscretization_(bitsPrecision, coefficients);
Message($"One-norm {oneNorm}");
// Reconstruct coefficients
mutable coefficientsOutInt = new Int[coeffs];
for (idx in 0..coeffs-1)
{
set coefficientsOutInt[idx] = coefficientsOutInt[idx] + keepCoeff[idx];
if (altIndex[idx] >= 0)
{
set coefficientsOutInt[altIndex[idx]] = coefficientsOutInt[altIndex[idx]] + barHeight - keepCoeff[idx];
}
}
// Reconstruct coefficients
mutable coefficientsOut = new Double[coeffs];
mutable errors = new Double[coeffs];
mutable maxError = 0.0;
for (i in 0..coeffs-1)
{
set coefficientsOut[i] = oneNorm * ToDouble(coefficientsOutInt[i]) / ToDouble(barHeight * coeffs);
let error = AbsD(coefficients[i] - coefficientsOut[i]) / oneNorm /( PowD(2.0, ToDouble(-bitsPrecision)) / ToDouble(coeffs));
set errors[i] = error;
if(AbsD(error) > AbsD(maxError)){
set maxError = error;
}
}
Message($"coeffs {coeffs}, bitsPrecision {bitsPrecision}, maxError {maxError}");
for(i in 0..coeffs-1){
if(errors[i] < ToDouble(3)){
// test passes
}
else{
fail $"index {i} reconstruced cofficient incorrect. Error is {errors[i]}";
}
}
}
}
operation QuantumROMTest() : Unit {
for(coeffs in 2..7){
for(nBitsPrecision in -1..-1..-2){
let targetError = PowD(2.0, ToDouble(nBitsPrecision));
let probtargetError = targetError / ToDouble(coeffs);
mutable coefficients = new Double[coeffs];
for (idx in 0..coeffs-1)
{
set coefficients[idx] = RandomReal(2*32);
}
let ((nTotal, (nCoeffQubits, nGarbageQubits)), oneNorm, op) = QuantumROM(targetError, coefficients);
Message($"Test case coeffs {coeffs}, bitsPrecision {nCoeffQubits}, global targetError {targetError}, probability error {probtargetError}.");
for (idx in 0..coeffs-1)
{
let tmp = AbsD(coefficients[idx]) / oneNorm;
Message($"{idx} expected prob = {tmp}.");
}
Message($"Qubits used: {nGarbageQubits} + {nCoeffQubits}");
using(qubits = Qubit[nTotal]){
let (register, rest) = QuantumROMQubitManager_(targetError, coeffs, qubits);
let (coeffQubits, garbageQubits) = register;
op(register);
// Now check that probability of each number state in nCoeffQubits is as expected.
for(stateIndex in 0..coeffs-1){
let prob = AbsD(coefficients[stateIndex]) / oneNorm;
Message($"Testing probability {prob} on index {stateIndex}");
//BAssertProbIntBE(stateIndex, AbsD(coefficients[stateIndex]) / oneNorm, BigEndian(coeffQubits), targetError / ToDouble(coeffs));
}
(Adjoint op)(register);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,218 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Convert;
// BlockEncoding.qs tests
// The returned operations encode the Hamiltonian (cos^2(angle) I+sin^2(angle) X)/2.
function LCUTestHelper() : (Double[], Double, Double, (Qubit[] => () : Adjoint, Controlled), ((Qubit[], Qubit[]) => Unit : Adjoint, Controlled)){
let angle = 1.789;
let eigenvalues = [0.5, 0.5 * Cos(angle * 2.0)];
let prob = PowD(Cos(angle),4.0)+PowD(Sin(angle),4.0);
let inverseAngle = ArcSin(PowD(Sin(angle),2.0)/Sqrt(prob));
let statePreparation = Exp([PauliY], angle, _);
let selector = Controlled (ApplyToEachCA(X, _))(_, _);
return (eigenvalues, prob, inverseAngle, statePreparation, selector);
}
// This checks that BlockEncodingByLCU encodes the correct Hamiltonian.
operation BlockEncodingByLCUTest() : Unit {
body (...) {
let (eigenvalues, prob, inverseAngle, statePreparation, selector) = LCUTestHelper();
let LCU = BlockEncodingByLCU(statePreparation, selector);
using(qubits = Qubit[2]){
let auxillary = [qubits[0]];
let system = [qubits[1]];
for(rep in 0..5){
LCU(auxillary, system);
AssertProb([PauliZ], auxillary, Zero, prob, "Error0: Z Success probability does not match theory", 1e-10);
let result = M(auxillary[0]);
if(result == Zero) {
Exp([PauliY],1.0 * inverseAngle, system);
AssertProb([PauliZ], system, Zero, 1.0, "Error1: Z Success probability does not match theory", 1e-10);
}
ResetAll(qubits);
}
}
}
}
// This checks that BlockEncodingReflectionByLCU encodes the correct Hamiltonian.
operation BlockEncodingReflectionByLCUTest() : Unit {
body (...) {
let (eigenvalues, prob, inverseAngle, statePreparation, selector) = LCUTestHelper();
let LCU = BlockEncodingReflectionByLCU(statePreparation, selector);
using(qubits = Qubit[4]){
let auxillary = qubits[2..3];
let system = [qubits[0]];
let flag = qubits[1];
for (rep in 0..5) {
LCU!!(auxillary, system);
X(flag);
(ControlledOnInt(0, X))(auxillary, flag);
AssertProb([PauliZ],[flag], Zero, prob, "Error0: Z Success probability does not match theory", 1e-10);
let result = M(flag);
if(result == Zero) {
Exp([PauliY],1.0 * inverseAngle, system);
AssertProb([PauliZ], system, Zero, 1.0, "Error1: Z Success probability does not match theory", 1e-10);
}
ResetAll(qubits);
}
}
}
}
// This checks that QuantumWalkByQubitization encodes the correct Hamiltonian.
operation QuantumWalkByQubitizationTest() : Unit {
body (...) {
let (eigenvalues, prob, inverseAngle, statePreparation, selector) = LCUTestHelper();
let LCU = QuantumWalkByQubitization(BlockEncodingReflectionByLCU(statePreparation, selector));
using(qubits = Qubit[4]){
let auxillary = qubits[2..3];
let system = [qubits[0]];
let flag = qubits[1];
for(rep in 0..5){
LCU(auxillary, system);
X(flag);
(ControlledOnInt(0, X))(auxillary, flag);
AssertProb([PauliZ],[flag], Zero, prob, "Error0: Z Success probability does not match theory", 1e-10);
let result = M(flag);
if(result == Zero) {
Exp([PauliY],1.0 * inverseAngle, system);
AssertProb([PauliZ], system, Zero, 1.0, "Error1: Z Success probability does not match theory", 1e-10);
}
ResetAll(qubits);
}
}
}
}
// QubitizationPauliEvolutionSet.qs tests
// This encodes the Hamiltonian (cos^2(angle) I+sin^2(angle) X)/2.
operation PauliBlockEncodingLCUTest() : Unit {
body (...) {
let angle = 0.123;
let cosSquared = Cos(angle) * Cos(angle);
let prob = PowD(Cos(angle),4.0)+PowD(Sin(angle),4.0);
let inverseAngle = ArcSin(PowD(Sin(angle),2.0)/Sqrt(prob));
mutable genIndices = new GeneratorIndex[2];
set genIndices[0] = GeneratorIndex(([0],[cosSquared]),[0]);
set genIndices[1] = GeneratorIndex(([1],[1.0-cosSquared]),[0]);
let generatorSystem = GeneratorSystem(2, LookupFunction(genIndices));
let (norm, LCU) = PauliBlockEncoding(generatorSystem);
using (qubits = Qubit[2]) {
let auxillary = [qubits[0]];
let system = [qubits[1]];
for (rep in 0..5) {
LCU!!(auxillary, system);
AssertProb([PauliZ], auxillary, Zero, prob, "Error0: Z Success probability does not match theory", 1e-10);
let result = M(auxillary[0]);
if(result == Zero) {
Exp([PauliY],1.0 * inverseAngle, system);
AssertProb([PauliZ], system, Zero, 1.0, "Error1: Z Success probability does not match theory", 1e-10);
}
ResetAll(qubits);
}
}
}
}
// Array.qs tests
function IntArrayFromRangeTest() : Unit {
mutable testCases = new (Int[], Range)[4];
let e = new Int[0];
set testCases[0] = ([1, 3, 5, 7], 1..2..8);
set testCases[1] = ([9, 6, 3, 0, -3], 9..-3..-3);
set testCases[2] = (e, 0..2..-1);
set testCases[3] = ([0], 0..4..3);
for (idxTest in 0..Length(testCases) - 1) {
let (expected, range) = testCases[idxTest];
let output = IntArrayFromRange(range);
Ignore(Map(AssertIntEqual(_, _, "Pad failed."), Zip(output, expected)));
}
}
operation InPlaceMajorityTest() : Unit {
body (...) {
// Majority function truth table: x;y;z | output
let testCases = [[false, false, false, false],
[false, false, true, false],
[false, true, false, false],
[false, true, true, true],
[ true, false, false, false],
[ true, false, true, true],
[ true, true, false, true],
[ true, true, true, true]];
using (qubits = Qubit[3]) {
for(idxTest in 0..Length(testCases)-1){
let testCase = testCases[idxTest];
Message($"Test case {idxTest}.");
for(idxQubit in 0..2){
if(testCase[idxQubit]){
X(qubits[idxQubit]);
}
}
InPlaceMajority(qubits[0], qubits[1..2]);
if(testCase[3] == false){
AssertProb([PauliZ], qubits[0..0], Zero, 1.0, "", 1e-10);
}
else{
AssertProb([PauliZ], qubits[0..0], One, 1.0, "", 1e-10);
}
ResetAll(qubits);
}
}
}
}
operation ApplyRippleCarryComparatorTest() : Unit{
body (...) {
let nQubits = 4;
let intMax = 2^nQubits-1;
for(x in 0..intMax){
for(y in 0..intMax){
mutable result = Zero;
if(x > y){
set result = One;
}
Message($"Test case. {x} > {y} = {result}");
using(qubits = Qubit[nQubits*2 + 1]){
let xRegister = BigEndian(qubits[0..nQubits-1]);
let yRegister = BigEndian(qubits[nQubits..2*nQubits-1]);
let output = qubits[2*nQubits];
InPlaceXorBE(x, xRegister);
InPlaceXorBE(y, yRegister);
ApplyRippleCarryComparatorBE(xRegister, yRegister, output);
AssertProb([PauliZ], [output], result, 1.0, "", 1e-10);
if(result == One){
X(output);
}
(Adjoint InPlaceXorBE)(y, yRegister);
(Adjoint InPlaceXorBE)(x, xRegister);
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
/// # Summary
/// Checks that @"microsoft.quantum.canon.randomint" obeys ranges.
operation RandomIntRangeTest () : Unit {
let randomInt = RandomInt(45);
if (randomInt > 45 || randomInt < 0) {
fail $"RandomInt returned an integer outside the allowed range.";
}
}
/// # Summary
/// Checks that @"microsoft.quantum.canon.randomintpow2" obeys ranges.
operation RandomIntPow2RangeTest () : Unit {
let randIntPow2 = RandomIntPow2(7);
if (randIntPow2 > 127 || randIntPow2 < 0) {
fail $"RandomIntPow2 returned an integer outside the allowed range.";
}
}
}

Просмотреть файл

@ -0,0 +1,304 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Tests {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
// number of qubits, abs(amplitude), phase
newtype StatePreparationTestCase = (Int, Double[], Double[]);
operation StatePreparationPositiveCoefficientsTest () : Unit {
let tolerance = 1E-09;
mutable testCases = new StatePreparationTestCase[100];
mutable nTests = 0;
// Test positive coefficients.
set testCases[nTests] = StatePreparationTestCase(1, [0.773761, 0.633478], [0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(2, [0.183017, 0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [0.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(4, [0.271471, 0.0583654, 0.11639, 0.36112, 0.307383, 0.193371, 0.274151, 0.332542, 0.130172, 0.222546, 0.314879, 0.210704, 0.212429, 0.245518, 0.30666, 0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
// Test negative coefficients. Should give same probabilities as positive coefficients.
set testCases[nTests] = StatePreparationTestCase(1, [-0.773761, 0.633478], [0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(2, [0.183017, -0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [0.0986553, -0.359005, 0.465689, -0.467395, 0.419893, 0.118445, -0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(4, [-0.271471, 0.0583654, 0.11639, 0.36112, -0.307383, 0.193371, -0.274151, 0.332542, 0.130172, 0.222546, 0.314879, -0.210704, 0.212429, 0.245518, -0.30666, -0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
// Test unnormalized coefficients
set testCases[nTests] = StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], new Double[0]);
set nTests = nTests + 1;
// Test missing coefficicients
set testCases[nTests] = StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445], new Double[0]);
set nTests = nTests + 1;
// Loop over multiple qubit tests
for (idxTest in 0 .. nTests - 1) {
let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!;
let nCoefficients = Length(coefficientsAmplitude);
// Test negative coefficicients. Should give same results as positive coefficients.
using (qubits = Qubit[nQubits]) {
let qubitsBE = BigEndian(qubits);
let op = StatePreparationPositiveCoefficients(coefficientsAmplitude);
op(qubitsBE);
let normalizedCoefficients = PNormalize(2.0, coefficientsAmplitude);
for (idxCoeff in 0 .. nCoefficients - 1) {
let amp = normalizedCoefficients[idxCoeff];
let prob = amp * amp;
AssertProbIntBE(idxCoeff, prob, qubitsBE, tolerance);
}
ResetAll(qubits);
}
}
}
// Test phase factor on 1-qubit uniform superposition.
operation StatePreparationComplexCoefficientsQubitPhaseTest () : Unit {
let tolerance = 1E-09;
mutable testCases = new StatePreparationTestCase[10];
mutable nTests = 0;
// Test phase factor on uniform superposition.
set testCases[nTests] = StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.05]);
set nTests = nTests + 1;
// Loop over tests
for (idxTest in 0 .. nTests - 1) {
let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!;
Message($"Test case {idxTest}");
let nCoefficients = Length(coefficientsAmplitude);
using (qubits = Qubit[nQubits]) {
let qubitsBE = BigEndian(qubits);
mutable coefficients = new ComplexPolar[nCoefficients];
mutable coefficientsPositive = new Double[nCoefficients];
for (idxCoeff in 0 .. nCoefficients - 1) {
set coefficients[idxCoeff] = ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]);
set coefficientsPositive[idxCoeff] = coefficientsAmplitude[idxCoeff];
}
let normalizedCoefficients = PNormalize(2.0, coefficientsAmplitude);
// Test phase factor on uniform superposition
let phase = 0.5 * (coefficientsPhase[0] - coefficientsPhase[1]);
let amp = normalizedCoefficients[0];
let prob = amp * amp;
let op = StatePreparationComplexCoefficients(coefficients);
op(qubitsBE);
AssertProbIntBE(0, prob, qubitsBE, tolerance);
AssertProbIntBE(1, prob, qubitsBE, tolerance);
AssertPhase(phase, (qubitsBE!)[0], tolerance);
ResetAll(qubits);
}
}
}
// Test probabilities and phases factor of multi-qubit uniform superposition.
operation StatePreparationComplexCoefficientsMultiQubitPhaseTest () : Unit {
let tolerance = 1E-09;
mutable testCases = new StatePreparationTestCase[10];
mutable nTests = 0;
// Test probability and phases of uniform superposition.
set testCases[nTests] = StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [PI(), PI(), PI(), PI(), PI(), PI(), PI(), PI()]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]);
set nTests = nTests + 1;
// Loop over tests
for (idxTest in 0 .. nTests - 1) {
let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!;
Message($"Test case {idxTest}");
let nCoefficients = Length(coefficientsAmplitude);
using (qubits = Qubit[nQubits]) {
let qubitsBE = BigEndian(qubits);
mutable coefficients = new ComplexPolar[nCoefficients];
mutable coefficientsPositive = new Double[nCoefficients];
for (idxCoeff in 0 .. nCoefficients - 1) {
set coefficients[idxCoeff] = ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]);
set coefficientsPositive[idxCoeff] = coefficientsAmplitude[idxCoeff];
}
let normalizedCoefficients = PNormalize(2.0, coefficientsAmplitude);
// Test probability and phases of uniform superposition
let op = StatePreparationComplexCoefficients(coefficients);
using (control = Qubit[1]) {
// Test probability
H(control[0]);
Controlled op(control, qubitsBE);
X(control[0]);
Controlled (ApplyToEachCA(H, _))(control, qubitsBE!);
X(control[0]);
for (idxCoeff in 0 .. nCoefficients - 1) {
let amp = normalizedCoefficients[idxCoeff];
let prob = amp * amp;
AssertProbIntBE(idxCoeff, prob, qubitsBE, tolerance);
}
ResetAll(control);
ResetAll(qubits);
//Test phase
for (repeats in 0 .. nCoefficients / 2) {
H(control[0]);
Controlled op(control, qubitsBE);
X(control[0]);
Controlled (ApplyToEachCA(H, _))(control, qubitsBE!);
X(control[0]);
let indexMeasuredInteger = MeasureIntegerBE(qubitsBE);
let phase = coefficientsPhase[indexMeasuredInteger];
Message($"StatePreparationComplexCoefficientsTest: expected phase = {phase}.");
AssertPhase(-0.5 * phase, control[0], tolerance);
ResetAll(control);
ResetAll(qubits);
}
}
}
}
}
// Test probabilities and phases of arbitrary multi-qubit superposition.
operation StatePreparationComplexCoefficientsArbitraryMultiQubitPhaseTest () : Unit {
let tolerance = 1E-09;
mutable testCases = new StatePreparationTestCase[10];
mutable nTests = 0;
set testCases[nTests] = StatePreparationTestCase(1, [1.0986553, 0.359005], [0.419893, 0.118445]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(2, [1.0986553, 0.359005, -0.123, 9.238], [0.419893, 0.118445, -0.467395, 0.419893]);
set nTests = nTests + 1;
set testCases[nTests] = StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.123, 9.238], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]);
set nTests = nTests + 1;
// Loop over tests
for (idxTest in 0 .. nTests - 1) {
let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!;
Message($"Test case {idxTest}");
let nCoefficients = Length(coefficientsAmplitude);
using (qubits = Qubit[nQubits]) {
let qubitsBE = BigEndian(qubits);
mutable coefficients = new ComplexPolar[nCoefficients];
mutable coefficientsPositive = new Double[nCoefficients];
for (idxCoeff in 0 .. nCoefficients - 1) {
set coefficients[idxCoeff] = ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]);
set coefficientsPositive[idxCoeff] = coefficientsAmplitude[idxCoeff];
}
let normalizedCoefficients = PNormalize(2.0, coefficientsAmplitude);
// Test probability and phases of arbitrary superposition
let opComplex = StatePreparationComplexCoefficients(coefficients);
let opReal = StatePreparationPositiveCoefficients(coefficientsPositive);
using (control = Qubit[1]) {
// Test probability
H(control[0]);
Controlled opComplex(control, qubitsBE);
X(control[0]);
Controlled opReal(control, qubitsBE);
X(control[0]);
for (idxCoeff in 0 .. nCoefficients - 1) {
let amp = normalizedCoefficients[idxCoeff];
let prob = amp * amp;
AssertProbIntBE(idxCoeff, prob, qubitsBE, tolerance);
}
ResetAll(control);
ResetAll(qubits);
// Test phase
for (repeats in 0 .. nCoefficients / 2) {
H(control[0]);
Controlled opComplex(control, qubitsBE);
X(control[0]);
Controlled opReal(control, qubitsBE);
X(control[0]);
let indexMeasuredInteger = MeasureIntegerBE(qubitsBE);
let phase = coefficientsPhase[indexMeasuredInteger];
Message($"StatePreparationComplexCoefficientsTest: expected phase = {phase}.");
AssertPhase(-0.5 * phase, control[0], tolerance);
ResetAll(control);
ResetAll(qubits);
}
}
}
}
}
operation PrepareUniformSuperpositionTest() : Unit {
body (...) {
let nQubits = 5;
using(qubits = Qubit[nQubits])
{
for(nIndices in 1..2^nQubits)
{
Message($"Testing nIndices {nIndices} on {nQubits} qubits");
PrepareUniformSuperposition(nIndices, BigEndian(qubits));
ApplyToEachCA(H,qubits);
using(flag = Qubit[1])
{
(ControlledOnInt(0, X))(qubits, flag[0]);
AssertProb([PauliZ], flag, One, ToDouble(nIndices)/ToDouble(2^nQubits), "", 1e-10);
(ControlledOnInt(0, X))(qubits, flag[0]);
ApplyToEachCA(H,qubits);
let measuredInt = MeasureIntegerBE(BigEndian(qubits));
if(measuredInt >= nIndices){
fail $"Measured integer {measuredInt} which is bigger than expected of number state {nIndices}.";
}
ResetAll(flag);
}
ResetAll(qubits);
}
}
}
}
}

77
Chemistry.sln Normal file
Просмотреть файл

@ -0,0 +1,77 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{561759D2-4D2D-4EE3-9565-9AAEC4A7D64B}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Runtime", "Chemistry\src\Runtime\Runtime.csproj", "{795ED042-3FF8-4349-902B-4EBD385F221E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataModel", "Chemistry\src\DataModel\DataModel.csproj", "{0A9803CC-C14F-49AF-9694-3DEC751EEA81}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{F561BE56-63D8-4C33-A3B3-CF2685BC7A5C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{595D5855-8820-48D7-B5E1-9C88215A866A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemTests", "Chemistry\tests\SystemTests\SystemTests.csproj", "{E9688DB1-CECC-407E-A192-90CC07FC48CA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataModelTests", "Chemistry\tests\DataModelTests\DataModelTests.csproj", "{56296CAB-76A9-4595-B5DB-DC8290B9B991}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChemistryTests", "Chemistry\tests\ChemistryTests\ChemistryTests.csproj", "{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canon", "Canon\src\Canon.csproj", "{4EE69CC7-1158-49A2-A28F-9443B06D4A32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{795ED042-3FF8-4349-902B-4EBD385F221E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{795ED042-3FF8-4349-902B-4EBD385F221E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{795ED042-3FF8-4349-902B-4EBD385F221E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{795ED042-3FF8-4349-902B-4EBD385F221E}.Release|Any CPU.Build.0 = Release|Any CPU
{0A9803CC-C14F-49AF-9694-3DEC751EEA81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A9803CC-C14F-49AF-9694-3DEC751EEA81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A9803CC-C14F-49AF-9694-3DEC751EEA81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A9803CC-C14F-49AF-9694-3DEC751EEA81}.Release|Any CPU.Build.0 = Release|Any CPU
{E9688DB1-CECC-407E-A192-90CC07FC48CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9688DB1-CECC-407E-A192-90CC07FC48CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9688DB1-CECC-407E-A192-90CC07FC48CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9688DB1-CECC-407E-A192-90CC07FC48CA}.Release|Any CPU.Build.0 = Release|Any CPU
{56296CAB-76A9-4595-B5DB-DC8290B9B991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56296CAB-76A9-4595-B5DB-DC8290B9B991}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56296CAB-76A9-4595-B5DB-DC8290B9B991}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56296CAB-76A9-4595-B5DB-DC8290B9B991}.Release|Any CPU.Build.0 = Release|Any CPU
{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD}.Release|Any CPU.Build.0 = Release|Any CPU
{4EE69CC7-1158-49A2-A28F-9443B06D4A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EE69CC7-1158-49A2-A28F-9443B06D4A32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EE69CC7-1158-49A2-A28F-9443B06D4A32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EE69CC7-1158-49A2-A28F-9443B06D4A32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{795ED042-3FF8-4349-902B-4EBD385F221E} = {F561BE56-63D8-4C33-A3B3-CF2685BC7A5C}
{0A9803CC-C14F-49AF-9694-3DEC751EEA81} = {F561BE56-63D8-4C33-A3B3-CF2685BC7A5C}
{E9688DB1-CECC-407E-A192-90CC07FC48CA} = {595D5855-8820-48D7-B5E1-9C88215A866A}
{56296CAB-76A9-4595-B5DB-DC8290B9B991} = {595D5855-8820-48D7-B5E1-9C88215A866A}
{F723F015-C78C-46A2-BB9D-CD2FD3D1DDCD} = {595D5855-8820-48D7-B5E1-9C88215A866A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6869E5BF-551A-40F1-9B6B-D1B27A5676CB}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

50
Chemistry/README.md Normal file
Просмотреть файл

@ -0,0 +1,50 @@
# Microsoft Quantum Chemistry Library.
C# and Q# sources used to implement the Microsoft Quantum Chemistry library. Samples and tests included.
## Outline of features
- Load a chemistry Hamiltonian from file. Supported format are:
- LiQui|> schema
- YAML schema
- Pass loaded Hamiltonian to a variety of simulation algorithm.
- Trotter simulation
- Optimized Trotter simulation
- Qubitization with minimal qubit overhead
- Qubitization with minimal T-gate overhead
- Samples for learning how to use the library, and also for performing quantum simulations of ground state energy estimation and obtaining resource estimates of simulation algorithms.
## Verify Installation
- If using Microsoft Visual Studio:
1. Open 'Microsoft.Quantum.Chemistry.sln'.
2. Select Samples/1 - MolecularHydrogen/MolecularHydrogenGUI as the StartUp project.
3. Press F5 to run the molecular Hydrogen quantum phase estimation demo.
- If using Windows command line:
1. Go to [RunSimulation](../Samples/Chemistry/MolecularHydrogenGUI).
2. Enter 'dotnet run' to run molecular Hydrogen quantum phase estimation demo.
## Structure of the Library
- **[DataModel](src/DataModel/)**:
This is a C# library that handles loading a chemistry Hamiltonian from file into a standard format. This library also handles classical preprocessing & optimization of the standard format to a format specialized for consumption by various Q# simulation algorithms.
- **[Chemistry](src/Chemistry/)**:
This Q# library contains methods specific to simulating chemistry Hamiltonians that are output by the DataModel library.
- **[CanonAdditions](src/CanonAdditions/)**:
This Q# library contains methods that will be eventually merged with the Microsoft.Quantum.Canon library.
## Structure of the tests
- **[DataModelTests](tests/DataModelTests/)**:
Contains tests for the C# component of handling the chemistry Hamiltonian and loading them from files.
- **[ChemistryTests](tests/ChemistryTests/)**:
Contains tests for isolated Q# component of simulating chemistry Hamiltonians.
- **[SystemTests](tests/SystemTests/)**:
Contains tests for simulating chemistry Hamiltonians that are output by the DataModel library.
## Structure of the samples
See the README in [Chemistry library samples](../Samples/Chemistry).

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше