Release/v0.3.1810 (#1)
* 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:
Родитель
e8743d675f
Коммит
038ddfd42e
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
29
.travis.yml
29
.travis.yml
|
@ -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
|
||||
|
|
@ -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
|
Двоичный файл не отображается.
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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}.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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⟫.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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).
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче