diff --git a/Simulation.sln b/Simulation.sln
index 2566fb7b457..44e5a43c5b9 100644
--- a/Simulation.sln
+++ b/Simulation.sln
@@ -57,6 +57,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library2", "src\Simulation\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "src\Simulation\Simulators.Tests\TestProjects\UnitTests\UnitTests.csproj", "{46278108-D247-4EFC-AC34-23D4A676F62F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Quantum.QSharp.Base", "src\Simulation\QsharpBase\Microsoft.Quantum.QSharp.Base.csproj", "{E9E387C0-2881-4F0C-8433-064BB18DB742}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DecompositionsCore", "DecompositionsCore", "{4DF4699D-5A50-4B3F-8232-5B19CAE23950}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Quantum.Decompositions.Type2.Core", "src\Simulation\DecompositionsCore\Type2\Microsoft.Quantum.Decompositions.Core.Type2.csproj", "{C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DecompositionsCore.Test", "DecompositionsCore.Test", "{2593CE5E-AFD0-4AF0-B816-0E263201E726}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Type2DecompositionsTests", "src\Simulation\DecompositionsCore.Test\Type2\Type2DecompositionsTests.csproj", "{05C78D61-BAB4-459D-8E7E-72071BFC5FBB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -389,6 +399,54 @@ Global
{46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{46278108-D247-4EFC-AC34-23D4A676F62F}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Debug|x64.Build.0 = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.MinSizeRel|x64.Build.0 = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Release|x64.ActiveCfg = Release|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.Release|x64.Build.0 = Release|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
+ {E9E387C0-2881-4F0C-8433-064BB18DB742}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Debug|x64.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.MinSizeRel|x64.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Release|x64.ActiveCfg = Release|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.Release|x64.Build.0 = Release|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Debug|x64.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.MinSizeRel|x64.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Release|x64.ActiveCfg = Release|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.Release|x64.Build.0 = Release|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -416,6 +474,12 @@ Global
{7256B986-6705-42FC-9F57-485D72D9DE51} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820}
{A85277B3-4E07-4E15-8F0C-07CC855A3BCB} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820}
{46278108-D247-4EFC-AC34-23D4A676F62F} = {09C842CB-930C-4C7D-AD5F-E30DE4A55820}
+ {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4} = {99E234BC-997E-4E63-9F5C-3C3977543404}
+ {E9E387C0-2881-4F0C-8433-064BB18DB742} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4}
+ {4DF4699D-5A50-4B3F-8232-5B19CAE23950} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4}
+ {C548F9AA-DD12-4C39-BC75-8458CBCDB1D5} = {4DF4699D-5A50-4B3F-8232-5B19CAE23950}
+ {2593CE5E-AFD0-4AF0-B816-0E263201E726} = {34D419E9-CCF1-4E48-9FA4-3AD4B86BEEB4}
+ {05C78D61-BAB4-459D-8E7E-72071BFC5FBB} = {2593CE5E-AFD0-4AF0-B816-0E263201E726}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821}
diff --git a/build/pack.ps1 b/build/pack.ps1
index b4b39f19e2a..617b2a61d12 100644
--- a/build/pack.ps1
+++ b/build/pack.ps1
@@ -62,7 +62,9 @@ Write-Host "##[info]Using nuget to create packages"
Pack-Dotnet '../src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj'
Pack-One '../src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj' '-IncludeReferencedProjects'
Pack-Dotnet '../src/Simulation/Core/Microsoft.Quantum.Runtime.Core.csproj'
+Pack-Dotnet '../src/Simulation/QsharpBase/Microsoft.Quantum.QSharp.Base.csproj'
Pack-Dotnet '../src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj'
+Pack-Dotnet '../src/Simulation/DecompositionsCore/Type2/Microsoft.Quantum.Decompositions.Core.Type2.csproj'
Pack-One '../src/Simulation/Simulators/Microsoft.Quantum.Simulators.nuspec'
Pack-One '../src/Quantum.Development.Kit/Microsoft.Quantum.Development.Kit.nuspec'
Pack-One '../src/Xunit/Microsoft.Quantum.Xunit.csproj'
diff --git a/src/Simulation/DecompositionsCore.Test/Common/DecompositionsTestCommon.csproj b/src/Simulation/DecompositionsCore.Test/Common/DecompositionsTestCommon.csproj
new file mode 100644
index 00000000000..7d4b8883565
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Common/DecompositionsTestCommon.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+
+ netcoreapp3.1
+ false
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Simulation/DecompositionsCore.Test/Common/IntrinsicExecute.qs b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicExecute.qs
new file mode 100644
index 00000000000..579385a00e2
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicExecute.qs
@@ -0,0 +1,153 @@
+// Methods in this file implement executing multiple variants of a given operator
+// to exercise its decompositions in all of those cases. For testing convenience
+// similar operators are grouped into a few batches.
+namespace IntrinsicTesting {
+
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+ open Microsoft.Quantum.Diagnostics;
+
+ //=========================================================================
+ // Groups of operators that can be tested together
+ //=========================================================================
+ operation ExecuteBasicInstrinsics(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ let eq = ExecuteWithAdjointAndControlledQ;
+ eq(intrinsics::X);
+ eq(intrinsics::Y);
+ eq(intrinsics::Z);
+ eq(intrinsics::H);
+ eq(intrinsics::S);
+ eq(intrinsics::T);
+ }
+
+ operation ExecuteSWAPandCNOT(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ let eq = ExecuteWithAdjointAndControlledQQ;
+ eq(intrinsics::CNOT);
+ eq(intrinsics::SWAP);
+ }
+
+ operation ExecuteRotations(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ let eq = ExecuteWithAdjointAndControlledDQ;
+ eq(intrinsics::Rx);
+ eq(intrinsics::Ry);
+ eq(intrinsics::Rz);
+ eq(intrinsics::R1);
+ }
+
+ operation ExecuteCCNOT(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledQQQ(intrinsics::CCNOT);
+ }
+
+ operation ExecuteR(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledPDQ(intrinsics::R);
+ }
+
+ operation ExecuteR1Frac(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledIIQ(intrinsics::R1Frac);
+ }
+
+ operation ExecuteRFrac(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledPIIQ(intrinsics::RFrac);
+ }
+
+ operation ExecuteExp(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledPADQA(intrinsics::Exp);
+ }
+
+ operation ExecuteExpFrac(intrinsics : UnitaryQSharpIntrinsics) : Unit {
+ ExecuteWithAdjointAndControlledPAIIQA(intrinsics::ExpFrac);
+ }
+
+ //=========================================================================
+ // Helpers for executing adjoint and controlled variants of an operator.
+ //=========================================================================
+ operation ExecuteOnQubitArray(nQubits : Int, op : (Qubit[] => Unit is Adj)) : Unit {
+ using( qubits = Qubit[nQubits] ) {
+ op(qubits);
+ Adjoint op(qubits);
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlled<'TupleT>(op : ('TupleT => Unit is Adj + Ctl), tupleMapper : (Qubit[] -> (Qubit[], 'TupleT)), tupleSize : Int) : Unit {
+ let op_composed = ApplyComposedA(Controlled op, tupleMapper, _);
+ Microsoft.Quantum.Intrinsic.Message($"Executing {op}");
+
+ for (numQubits in tupleSize .. MaxControls() + tupleSize) {
+ Microsoft.Quantum.Intrinsic.Message($"Total number of qubits: {numQubits}");
+ for (repetition in 1 .. NumberOfTestRepetitions()) {
+ ExecuteOnQubitArray(numQubits, op_composed);
+ }
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledQ(op : (Qubit => Unit is Adj + Ctl)) : Unit {
+ ExecuteWithAdjointAndControlled(op, ArrayAsTupleAO, 1);
+ }
+
+ operation ExecuteWithAdjointAndControlledAQ(numQubits : Int, op : (Qubit[] => Unit is Adj + Ctl)) : Unit {
+ ExecuteWithAdjointAndControlled(op, ArrayAsTupleAA(numQubits,_), numQubits);
+ }
+
+ operation _ExecuteWithAdjointAndControlledAPQ(paulis : Pauli[], op : ((Pauli[],Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ Microsoft.Quantum.Intrinsic.Message($"Checking for Pauli: {paulis}.");
+ ExecuteWithAdjointAndControlledAQ(Length(paulis), op(paulis,_));
+ }
+
+ operation ExecuteWithAdjointAndControlledAPQ(op : ((Pauli[],Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (numQubits in 1 .. MaxTargets()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking with {numQubits} qubits.");
+ IterateThroughCartesianPowerP(numQubits, PaulisToTest(), _ExecuteWithAdjointAndControlledAPQ(_, op));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledPADQA(op : ((Pauli[],Double,Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (angle in AnglesToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking angle {angle}");
+ ExecuteWithAdjointAndControlledAPQ(op(_,angle,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledPAIIQA(op : ((Pauli[],Int,Int,Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (fraction in FractionsToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking fraction {fraction}");
+ let (numerator, denominatorPower) = fraction;
+ ExecuteWithAdjointAndControlledAPQ(op(_,numerator,denominatorPower,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledDQ(op : ((Double, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (angle in AnglesToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking angle {angle}");
+ ExecuteWithAdjointAndControlledQ(op(angle,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledPDQ(op : ((Pauli, Double, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (pauli in PaulisToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking Pauli: {pauli}");
+ ExecuteWithAdjointAndControlledDQ(op(pauli, _,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledIIQ(op : ((Int, Int, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (fraction in FractionsToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking fraction {fraction}");
+ let (numerator, denominatorPower) = fraction;
+ ExecuteWithAdjointAndControlledQ(op(numerator,denominatorPower,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledPIIQ(op : ((Pauli, Int, Int, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (pauli in PaulisToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking Pauli: {pauli}");
+ ExecuteWithAdjointAndControlledIIQ(op(pauli, _,_,_));
+ }
+ }
+
+ operation ExecuteWithAdjointAndControlledQQ(op : ((Qubit,Qubit) => Unit is Adj + Ctl)) : Unit {
+ ExecuteWithAdjointAndControlled(op, ArrayAsTupleAIOO, 2);
+ }
+
+ operation ExecuteWithAdjointAndControlledQQQ(op : ((Qubit,Qubit,Qubit) => Unit is Adj + Ctl)) : Unit {
+ ExecuteWithAdjointAndControlled(op, ArrayAsTupleAIOOO, 3);
+ }
+}
diff --git a/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Settings.qs b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Settings.qs
new file mode 100644
index 00000000000..e4cb374acff
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Settings.qs
@@ -0,0 +1,49 @@
+namespace IntrinsicTesting {
+ function MaxControls() : Int {
+ return 3;
+ }
+
+ function MaxTargets() : Int {
+ return 3;
+ }
+
+ function NumberOfTestRepetitions() : Int {
+ return 1;
+ }
+
+ function AnglesToTest() : Double[] {
+ let pi = Microsoft.Quantum.Math.PI();
+ return [
+ 0.0,
+ pi/8.0,
+ pi/4.0,
+ pi/2.0,
+ 3.0 * pi/4.0,
+ pi,
+ 5.0 * pi/4.0,
+ 3.0 * pi/2.0,
+ 2.0 * pi,
+ 3.0 * pi,
+ 4.0 * pi,
+ 0.1984 ];
+ }
+
+ function FractionsToTest() : (Int,Int)[] {
+ return [
+ (0,-1),
+ (1,1),
+ (-1,1),
+ (1,2),
+ (3,2),
+ (-3,2),
+ (-1,2),
+ (1,3),
+ (-1,3),
+ (3,4),
+ (-1,4),
+ //(1, 9223372036854775807),
+ (1, 13)
+ //(1, -13)
+ ];
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Utils.qs b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Utils.qs
new file mode 100644
index 00000000000..f553aa99e06
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting-Utils.qs
@@ -0,0 +1,264 @@
+namespace IntrinsicTesting {
+ open Microsoft.Quantum.Diagnostics;
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+
+ internal 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]);
+ }
+
+ internal operation ApplyToFirstQubitA (op : (Qubit => Unit is Adj), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) == 0) {
+ fail $"Must have at least one qubit to act on.";
+ }
+
+ op(register[0]);
+ }
+
+ adjoint invert;
+ }
+
+ internal operation ApplyToFirstQubitC (op : (Qubit => Unit is Ctl), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) == 0) {
+ fail $"Must have at least one qubit to act on.";
+ }
+
+ op(register[0]);
+ }
+
+ controlled distribute;
+ }
+
+ internal operation ApplyToFirstQubitCA (op : (Qubit => Unit is Adj + Ctl), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) == 0) {
+ fail $"Must have at least one qubit to act on.";
+ }
+
+ op(register[0]);
+ }
+
+ adjoint invert;
+ controlled distribute;
+ controlled adjoint distribute;
+ }
+
+ internal 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]);
+ }
+
+ internal operation ApplyToFirstTwoQubitsA (op : ((Qubit, Qubit) => Unit is Adj), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) < 2) {
+ fail $"Must have at least two qubits to act on.";
+ }
+
+ op(register[0], register[1]);
+ }
+
+ adjoint invert;
+ }
+
+ operation ApplyToFirstTwoQubitsC (op : ((Qubit, Qubit) => Unit is Ctl), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) < 2) {
+ fail $"Must have at least two qubits to act on.";
+ }
+
+ op(register[0], register[1]);
+ }
+
+ controlled distribute;
+ }
+
+ internal operation ApplyToFirstTwoQubitsCA (op : ((Qubit, Qubit) => Unit is Adj + Ctl), register : Qubit[]) : Unit {
+ body (...) {
+ if (Length(register) < 2) {
+ fail $"Must have at least two qubits to act on.";
+ }
+
+ op(register[0], register[1]);
+ }
+
+ adjoint invert;
+ controlled distribute;
+ controlled adjoint distribute;
+ }
+
+ internal 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]);
+ }
+
+ internal operation ApplyToFirstThreeQubitsA (op : ((Qubit, Qubit, Qubit) => Unit is Adj), 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]);
+ }
+
+ adjoint invert;
+ }
+
+ internal operation ApplyToFirstThreeQubitsC (op : ((Qubit, Qubit, Qubit) => Unit is Ctl), 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]);
+ }
+
+ controlled distribute;
+ }
+
+ internal operation ApplyToFirstThreeQubitsCA (op : ((Qubit, Qubit, Qubit) => Unit is Adj + Ctl), 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]);
+ }
+
+ adjoint invert;
+ controlled distribute;
+ controlled adjoint distribute;
+ }
+
+ internal operation AssertOperationsEqualReferencedQ1( actual : ((Qubit) => Unit), expected : ((Qubit) => Unit is Adj) ) : Unit {
+ AssertOperationsEqualReferenced(2, ApplyToFirstQubit(actual,_), ApplyToFirstQubitA(expected,_));
+ }
+
+ internal operation AssertOperationsEqualReferencedQ2( actual : ((Qubit,Qubit) => Unit), expected : ((Qubit,Qubit) => Unit is Adj) ) : Unit {
+ AssertOperationsEqualReferenced(2, ApplyToFirstTwoQubits(actual,_), ApplyToFirstTwoQubitsA(expected,_));
+ }
+
+ internal operation AssertOperationsEqualReferencedQ3( actual : ((Qubit,Qubit,Qubit) => Unit), expected : ((Qubit,Qubit,Qubit) => Unit is Adj) ) : Unit {
+ AssertOperationsEqualReferenced(3, ApplyToFirstThreeQubits(actual,_), ApplyToFirstThreeQubitsA(expected,_));
+ }
+
+ internal operation ApplySinglyControlledCA<'T>(op : ('T => Unit is Adj + Ctl), (control : Qubit, arg : 'T)) : Unit is Adj + Ctl {
+ Controlled op([control], arg);
+ }
+
+ internal operation ApplySinglyControlledCAQ2(op : ((Qubit,Qubit) => Unit is Adj + Ctl), (control : Qubit, qubit1 : Qubit, qubit2 : Qubit)) : Unit is Adj + Ctl {
+ Controlled op([control], (qubit1, qubit2));
+ }
+
+ internal function SinglyControlled<'T>(op : ('T => Unit is Adj + Ctl)) : ((Qubit,'T) => Unit is Adj + Ctl) {
+ return ApplySinglyControlledCA(op, _);
+ }
+
+ internal function SinglyControlledQ2(op : ((Qubit,Qubit) => Unit is Adj + Ctl)) : ((Qubit,Qubit,Qubit) => Unit is Adj + Ctl) {
+ return ApplySinglyControlledCAQ2(op, _);
+ }
+
+ internal function ArrayAsTupleO<'T>(arr : 'T[]) : 'T {
+ return (arr[0]);
+ }
+
+ internal function ArrayAsTupleAO<'T>(arr : 'T[]) : ('T[],'T) {
+ return (arr[1 .. Length(arr) - 1], arr[0]);
+ }
+
+ internal function ArrayAsTupleOO<'T>(arr : 'T[]) : ('T,'T) {
+ return (arr[0], arr[1]);
+ }
+
+ internal function ArrayAsTupleAIOO<'T>(arr : 'T[]) : ('T[],('T,'T)) {
+ return (arr[2 .. Length(arr) - 1], (arr[0], arr[1]));
+ }
+
+ internal function ArrayAsTupleOOO<'T>(arr : 'T[]) : ('T,'T,'T) {
+ return (arr[0], arr[1], arr[2]);
+ }
+
+ internal function ArrayAsTupleAIOOO<'T>(arr : 'T[]) : ('T[],('T,'T,'T)) {
+ return (arr[3 .. Length(arr) - 1], (arr[0], arr[1],arr[2]));
+ }
+
+ internal function ArrayAsTupleAA<'T>(secondArraySize : Int, arr : 'T[]) : ('T[],'T[]) {
+ return (arr[secondArraySize .. Length(arr) - 1], (arr[0 .. secondArraySize - 1]));
+ }
+
+ internal function ArrayAsTupleOOIO<'T>( arr : 'T[]) : (('T,'T),'T) {
+ return ((arr[0], arr[1]), arr[2]);
+ }
+
+ internal function ArrayAsTupleOIOO<'T>(arr : 'T[]) : ('T,('T,'T)) {
+ return (arr[0],(arr[1], arr[2]));
+ }
+
+ internal operation ApplyComposedCA<'U,'V>(op : ('U => Unit is Adj + Ctl), fn : ('V -> 'U), arg : 'V) : Unit is Ctl + Adj {
+ op(fn(arg));
+ }
+
+ internal operation ApplyComposedA<'U,'V>(op : ('U => Unit is Adj), fn : ('V -> 'U), arg : 'V) : Unit is Adj {
+ op(fn(arg));
+ }
+
+ internal operation ApplyComposedC<'U,'V>(op : ('U => Unit is Ctl), fn : ('V -> 'U), arg : 'V) : Unit is Ctl {
+ op(fn(arg));
+ }
+
+ internal operation ApplyComposed<'U,'V>(op : ('U => Unit), fn : ('V -> 'U), arg : 'V) : Unit {
+ op(fn(arg));
+ }
+
+ internal 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 w/= 0 <- arr[0] + 1;
+
+ for (i in 0 .. Length(arr) - 2) {
+ if (arr[i] == bounds[i]) {
+ set arr w/= i + 1 <- arr[i + 1] + 1;
+ set arr w/= i <- 0;
+ }
+ }
+
+ if (arr[Length(arr) - 1] == bounds[Length(arr) - 1]) {
+ set finished = true;
+ }
+ }
+ }
+
+ internal operation IterateThroughCartesianPower (power : Int, bound : Int, op : (Int[] => Unit)) : Unit {
+ mutable arr = new Int[power];
+
+ for (i in 0 .. power - 1) {
+ set arr w/= i <- bound;
+ }
+
+ IterateThroughCartesianProduct(arr, op);
+ }
+
+ internal operation IterateThroughCartesianPowerP (power : Int, values : Pauli[], op : (Pauli[] => Unit)) : Unit {
+ let opInt = ApplyComposed(op, Utils.ArrayFromIndiciesP(values,_),_);
+ IterateThroughCartesianPower(power, Length(values), opInt);
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting.qs b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting.qs
new file mode 100644
index 00000000000..66657878a1c
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Common/IntrinsicTesting.qs
@@ -0,0 +1,172 @@
+namespace IntrinsicTesting {
+
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+ open Microsoft.Quantum.Diagnostics;
+
+ newtype UnitaryQSharpIntrinsics = (
+ X : (Qubit => Unit is Adj + Ctl),
+ Y : (Qubit => Unit is Adj + Ctl),
+ Z : (Qubit => Unit is Adj + Ctl),
+ H : (Qubit => Unit is Adj + Ctl),
+ S : (Qubit => Unit is Adj + Ctl),
+ T : (Qubit => Unit is Adj + Ctl),
+ CNOT : ((Qubit,Qubit) => Unit is Adj + Ctl),
+ CCNOT : ((Qubit,Qubit,Qubit) => Unit is Adj + Ctl),
+ SWAP : ((Qubit,Qubit) => Unit is Adj + Ctl),
+ R : ((Pauli, Double, Qubit) => Unit is Adj + Ctl),
+ RFrac : ((Pauli, Int, Int, Qubit) => Unit is Adj + Ctl),
+ Rx : ((Double, Qubit) => Unit is Adj + Ctl),
+ Ry : ((Double, Qubit) => Unit is Adj + Ctl),
+ Rz : ((Double, Qubit) => Unit is Adj + Ctl),
+ R1 : ((Double, Qubit) => Unit is Adj + Ctl),
+ R1Frac : ((Int, Int, Qubit) => Unit is Adj + Ctl ),
+ Exp : ((Pauli[], Double, Qubit[]) => Unit is Adj + Ctl),
+ ExpFrac : ((Pauli[], Int, Int, Qubit[]) => Unit is Adj + Ctl)
+ );
+
+ function StandardIntrinsics() : UnitaryQSharpIntrinsics {
+ return UnitaryQSharpIntrinsics(
+ Microsoft.Quantum.Intrinsic.X,
+ Microsoft.Quantum.Intrinsic.Y,
+ Microsoft.Quantum.Intrinsic.Z,
+ Microsoft.Quantum.Intrinsic.H,
+ Microsoft.Quantum.Intrinsic.S,
+ Microsoft.Quantum.Intrinsic.T,
+ Microsoft.Quantum.Intrinsic.CNOT,
+ Microsoft.Quantum.Intrinsic.CCNOT,
+ Microsoft.Quantum.Intrinsic.SWAP,
+ Microsoft.Quantum.Intrinsic.R,
+ Microsoft.Quantum.Intrinsic.RFrac,
+ Microsoft.Quantum.Intrinsic.Rx,
+ Microsoft.Quantum.Intrinsic.Ry,
+ Microsoft.Quantum.Intrinsic.Rz,
+ Microsoft.Quantum.Intrinsic.R1,
+ Microsoft.Quantum.Intrinsic.R1Frac,
+ Microsoft.Quantum.Intrinsic.Exp,
+ Microsoft.Quantum.Intrinsic.ExpFrac);
+ }
+
+ function PaulisToTest() : Pauli[] {
+ return [PauliI, PauliX, PauliY, PauliZ];
+ }
+
+ operation AssertEqualWithAdjointAndControlled<'TupleT>(actual : ('TupleT => Unit is Adj + Ctl), expected : ('TupleT => Unit is Adj + Ctl), tupleMapper : (Qubit[] -> (Qubit[], 'TupleT) ), tupleSize : Int ) : Unit {
+ let actualOnArr = ApplyComposedA(Controlled actual,tupleMapper,_);
+ let expectedOnArr = ApplyComposedA(Controlled expected,tupleMapper,_);
+ Microsoft.Quantum.Intrinsic.Message($"Checking equality of operations {actual} and {expected}");
+ for (numQubits in tupleSize .. MaxControls() + tupleSize) {
+ Microsoft.Quantum.Intrinsic.Message($"Total number of qubits: {numQubits}");
+ for (repetition in 1 .. NumberOfTestRepetitions()) {
+ AssertOperationsEqualReferenced(numQubits, actualOnArr, expectedOnArr);
+ AssertOperationsEqualReferenced(numQubits, Adjoint actualOnArr, Adjoint expectedOnArr);
+ }
+ }
+ Microsoft.Quantum.Intrinsic.Message($"Operations {actual} and {expected} are equal as well as their adjoint and controlled versions up to {MaxControls()} controls");
+ }
+
+ operation AssertEqualWithAdjointAndControlledQ(actual : (Qubit => Unit is Adj + Ctl), expected : (Qubit => Unit is Adj + Ctl)) : Unit {
+ AssertEqualWithAdjointAndControlled(actual, expected, ArrayAsTupleAO, 1);
+ }
+
+ operation AssertEqualWithAdjointAndControlledAQ(numQubits : Int, actual : (Qubit[] => Unit is Adj + Ctl), expected : (Qubit[] => Unit is Adj + Ctl)) : Unit {
+ AssertEqualWithAdjointAndControlled(actual, expected, ArrayAsTupleAA(numQubits,_), numQubits);
+ }
+
+ operation _AssertEqualWithAdjointAndControlledAPQ(paulis : Pauli[], actual : ((Pauli[],Qubit[]) => Unit is Adj + Ctl), expected : ((Pauli[],Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ Microsoft.Quantum.Intrinsic.Message($"Checking for Pauli: {paulis}.");
+ AssertEqualWithAdjointAndControlledAQ(Length(paulis), actual(paulis,_), expected(paulis,_));
+ }
+
+ operation AssertEqualWithAdjointAndControlledAPQ(actual : ((Pauli[],Qubit[]) => Unit is Adj + Ctl), expected : ((Pauli[],Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (numQubits in 1 .. MaxTargets()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking with {numQubits} qubits.");
+ IterateThroughCartesianPowerP( numQubits, PaulisToTest(), _AssertEqualWithAdjointAndControlledAPQ(_,actual,expected));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledPADQA(actual : ((Pauli[],Double,Qubit[]) => Unit is Adj + Ctl), expected : ((Pauli[],Double,Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (angle in AnglesToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking angle {angle}");
+ AssertEqualWithAdjointAndControlledAPQ(actual(_,angle,_), expected(_,angle,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledPAIIQA(actual : ((Pauli[],Int,Int,Qubit[]) => Unit is Adj + Ctl), expected : ((Pauli[],Int,Int,Qubit[]) => Unit is Adj + Ctl)) : Unit {
+ for (fraction in FractionsToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking fraction {fraction}");
+ let (numerator, denominatorPower) = fraction;
+ AssertEqualWithAdjointAndControlledAPQ(actual(_,numerator,denominatorPower,_), expected(_,numerator,denominatorPower,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledDQ(actual : ((Double, Qubit) => Unit is Adj + Ctl), expected : ((Double, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (angle in AnglesToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking angle {angle}");
+ AssertEqualWithAdjointAndControlledQ(actual(angle,_), expected(angle,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledPDQ(actual : ((Pauli, Double, Qubit) => Unit is Adj + Ctl), expected : ((Pauli, Double, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (pauli in PaulisToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking Pauli: {pauli}");
+ AssertEqualWithAdjointAndControlledDQ(actual(pauli, _,_), expected(pauli, _,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledIIQ(actual : ((Int, Int, Qubit) => Unit is Adj + Ctl), expected : ((Int, Int, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (fraction in FractionsToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking fraction {fraction}");
+ let (numerator, denominatorPower) = fraction;
+ AssertEqualWithAdjointAndControlledQ(actual(numerator,denominatorPower,_), expected(numerator,denominatorPower,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledPIIQ(actual : ((Pauli, Int, Int, Qubit) => Unit is Adj + Ctl), expected : ((Pauli, Int, Int, Qubit) => Unit is Adj + Ctl)) : Unit {
+ for (pauli in PaulisToTest()) {
+ Microsoft.Quantum.Intrinsic.Message($"Checking Pauli: {pauli}");
+ AssertEqualWithAdjointAndControlledIIQ(actual(pauli, _,_,_), expected(pauli, _,_,_));
+ }
+ }
+
+ operation AssertEqualWithAdjointAndControlledQQ(actual : ((Qubit,Qubit) => Unit is Adj + Ctl), expected : ((Qubit,Qubit) => Unit is Adj + Ctl)) : Unit {
+ AssertEqualWithAdjointAndControlled(actual, expected, ArrayAsTupleAIOO, 2);
+ }
+
+ operation AssertEqualWithAdjointAndControlledQQQ(actual : ((Qubit,Qubit,Qubit) => Unit is Adj + Ctl), expected : ((Qubit,Qubit,Qubit) => Unit is Adj + Ctl)) : Unit {
+ AssertEqualWithAdjointAndControlled(actual, expected, ArrayAsTupleAIOOO, 3);
+ }
+
+ operation TestInstrinsics( actualIntrinsics : UnitaryQSharpIntrinsics, expectedIntrinsics : UnitaryQSharpIntrinsics ) : Unit {
+ if (true) {
+ let eq = AssertEqualWithAdjointAndControlledQ;
+ eq(actualIntrinsics::X, expectedIntrinsics::X);
+ eq(actualIntrinsics::Y, expectedIntrinsics::Y);
+ eq(actualIntrinsics::Z, expectedIntrinsics::Z);
+ eq(actualIntrinsics::H, expectedIntrinsics::H);
+ eq(actualIntrinsics::S, expectedIntrinsics::S);
+ eq(actualIntrinsics::T, expectedIntrinsics::T);
+ }
+
+ if (true) {
+ let eq = AssertEqualWithAdjointAndControlledQQ;
+ eq(actualIntrinsics::CNOT, expectedIntrinsics::CNOT);
+ eq(actualIntrinsics::SWAP, expectedIntrinsics::SWAP);
+ }
+
+ AssertEqualWithAdjointAndControlledQQQ(actualIntrinsics::CCNOT, expectedIntrinsics::CCNOT);
+ AssertEqualWithAdjointAndControlledPDQ(actualIntrinsics::R, expectedIntrinsics::R);
+
+ if (true) {
+ let eq = AssertEqualWithAdjointAndControlledDQ;
+ eq(actualIntrinsics::Rx, expectedIntrinsics::Rx);
+ eq(actualIntrinsics::Ry, expectedIntrinsics::Ry);
+ eq(actualIntrinsics::Rz, expectedIntrinsics::Rz);
+ eq(actualIntrinsics::R1, expectedIntrinsics::R1);
+ }
+
+ AssertEqualWithAdjointAndControlledIIQ(actualIntrinsics::R1Frac, expectedIntrinsics::R1Frac);
+ AssertEqualWithAdjointAndControlledPIIQ(actualIntrinsics::RFrac, expectedIntrinsics::RFrac);
+ AssertEqualWithAdjointAndControlledPADQA(actualIntrinsics::Exp, expectedIntrinsics::Exp);
+ AssertEqualWithAdjointAndControlledPAIIQA(actualIntrinsics::ExpFrac, expectedIntrinsics::ExpFrac);
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore.Test/Type2/Type2-Decompositions-Tests.qs b/src/Simulation/DecompositionsCore.Test/Type2/Type2-Decompositions-Tests.qs
new file mode 100644
index 00000000000..0dbc110fdee
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Type2/Type2-Decompositions-Tests.qs
@@ -0,0 +1,90 @@
+namespace Type2.Decompositions.Tests {
+
+ function Type2Decompositions() : IntrinsicTesting.UnitaryQSharpIntrinsics {
+ return IntrinsicTesting.UnitaryQSharpIntrinsics(
+ Test.Decompositions.X,
+ Test.Decompositions.Y,
+ Test.Decompositions.Z,
+ Test.Decompositions.H,
+ Test.Decompositions.S,
+ Test.Decompositions.T,
+ Test.Decompositions.CNOT,
+ Test.Decompositions.CCNOT,
+ Test.Decompositions.SWAP,
+ Test.Decompositions.R,
+ Test.Decompositions.RFrac,
+ Test.Decompositions.Rx,
+ Test.Decompositions.Ry,
+ Test.Decompositions.Rz,
+ Test.Decompositions.R1,
+ Test.Decompositions.R1Frac,
+ Test.Decompositions.Exp,
+ Test.Decompositions.ExpFrac);
+ }
+
+ @Microsoft.Quantum.Diagnostics.Test("Test.Decompositions.Type2Simulator")
+ operation UnitaryIntrinsicTest() : Unit {
+ let standardIntrinsic = IntrinsicTesting.StandardIntrinsics();
+ let decompositions = Type2Decompositions();
+ IntrinsicTesting.TestInstrinsics(decompositions, standardIntrinsic);
+ }
+
+ // For running against Type2Processor simulator.
+ // Here the meaning of oracle and test target switch places: Type2 decompositions
+ // from this project become the reference, while the standard intrinsics implemented
+ // by the Type2Processor become the test target.
+ operation BasicGates_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteBasicInstrinsics(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation BasicGates_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteBasicInstrinsics(Type2Decompositions());
+ }
+ operation SWAPandCNOT_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteSWAPandCNOT(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation SWAPandCNOT_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteSWAPandCNOT(Type2Decompositions());
+ }
+ operation Rotations_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteSWAPandCNOT(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation Rotations_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteSWAPandCNOT(Type2Decompositions());
+ }
+ operation CCNOT_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteCCNOT(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation CCNOT_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteCCNOT(Type2Decompositions());
+ }
+ operation R_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteR(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation R_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteR(Type2Decompositions());
+ }
+ operation R1Frac_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteR1Frac(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation R1Frac_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteR1Frac(Type2Decompositions());
+ }
+ operation RFrac_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteRFrac(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation RFrac_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteRFrac(Type2Decompositions());
+ }
+ operation Exp_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteExp(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation Exp_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteExp(Type2Decompositions());
+ }
+ operation ExpFrac_Decompostion() : Unit {
+ IntrinsicTesting.ExecuteExpFrac(IntrinsicTesting.StandardIntrinsics());
+ }
+ operation ExpFrac_Decomposition_Type2Reference() : Unit {
+ IntrinsicTesting.ExecuteExpFrac(Type2Decompositions());
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore.Test/Type2/Type2DecompositionsTests.csproj b/src/Simulation/DecompositionsCore.Test/Type2/Type2DecompositionsTests.csproj
new file mode 100644
index 00000000000..64c98813abb
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Type2/Type2DecompositionsTests.csproj
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ netcoreapp3.1
+ false
+ false
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Simulation/DecompositionsCore.Test/Type2/Type2Simulator.cs b/src/Simulation/DecompositionsCore.Test/Type2/Type2Simulator.cs
new file mode 100644
index 00000000000..029490253c3
--- /dev/null
+++ b/src/Simulation/DecompositionsCore.Test/Type2/Type2Simulator.cs
@@ -0,0 +1,291 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Microsoft.Quantum.Simulation.Core;
+using Microsoft.Quantum.Simulation.Simulators;
+
+namespace Test.Decompositions
+{
+ public class Type2Simulator : QuantumSimulator
+ {
+ public Type2Simulator()
+ : base()
+ { }
+
+ public class Type2SimulatorX : X
+ {
+ private QuantumSimulator.QSimX Simulator { get; }
+
+ public Type2SimulatorX(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimX(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+ }
+
+ public class Type2SimulatorY : Y
+ {
+ private QuantumSimulator.QSimY Simulator { get; }
+
+ public Type2SimulatorY(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimY(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+ }
+
+ public class Type2SimulatorZ : Z
+ {
+ private QuantumSimulator.QSimZ Simulator { get; }
+
+ public Type2SimulatorZ(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimZ(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+ }
+
+ public class Type2SimulatorH : H
+ {
+ private QuantumSimulator.QSimH Simulator { get; }
+
+ public Type2SimulatorH(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimH(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+ }
+
+ public class Type2SimulatorS : S
+ {
+ private QuantumSimulator.QSimS Simulator { get; }
+
+ public Type2SimulatorS(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimS(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+
+ public override Func AdjointBody => Simulator.AdjointBody;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => Simulator.ControlledAdjointBody;
+ }
+
+ public class Type2SimulatorT : T
+ {
+ private QuantumSimulator.QSimT Simulator { get; }
+
+ public Type2SimulatorT(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimT(m);
+ }
+
+ public override Func Body => Simulator.Body;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledBody => Simulator.ControlledBody;
+
+ public override Func AdjointBody => Simulator.AdjointBody;
+
+ public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => Simulator.ControlledAdjointBody;
+ }
+
+ public class Type2SimulatorSWAP : SWAP
+ {
+ private QuantumSimulator.QSimX Simulator { get; }
+
+ public Type2SimulatorSWAP(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimX(m);
+ }
+
+ public override Func<(Qubit, Qubit), QVoid> Body => (args) =>
+ {
+ (Qubit q1, Qubit q2) = args;
+ Simulator.ControlledBody((new QArray(q1), q2));
+ Simulator.ControlledBody((new QArray(q2), q1));
+ Simulator.ControlledBody((new QArray(q1), q2));
+ return QVoid.Instance;
+ };
+
+ public override Func<(IQArray, (Qubit, Qubit)), QVoid> ControlledBody => (args) =>
+ {
+ (IQArray ctrls, (Qubit q1, Qubit q2)) = args;
+
+ if ((ctrls == null) || (ctrls.Count == 0))
+ {
+ Body((q1, q2));
+ }
+ else
+ {
+ Simulator.ControlledBody((QArray.Add(ctrls, new QArray(q1)), q2));
+ Simulator.ControlledBody((QArray.Add(ctrls, new QArray(q2)), q1));
+ Simulator.ControlledBody((QArray.Add(ctrls, new QArray(q1)), q2));
+ }
+
+ return QVoid.Instance;
+ };
+ }
+
+ public class Type2SimulatorR : R
+ {
+ private QuantumSimulator.QSimR Simulator { get; }
+
+ public Type2SimulatorR(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimR(m);
+ }
+
+ public override Func<(Pauli, double, Qubit), QVoid> Body => Simulator.Body;
+
+ public override Func<(Pauli, double, Qubit), QVoid> AdjointBody => Simulator.AdjointBody;
+
+ public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledBody => Simulator.ControlledBody;
+
+ public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledAdjointBody => Simulator.ControlledAdjointBody;
+ }
+
+ public class Type2SimulatorExp : Exp
+ {
+ private QuantumSimulator.QSimExp Simulator { get; }
+
+ public Type2SimulatorExp(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimExp(m);
+ }
+
+ public override Func<(IQArray, double, IQArray), QVoid> Body => Simulator.Body;
+
+ public override Func<(IQArray, double, IQArray), QVoid> AdjointBody => Simulator.AdjointBody;
+
+ public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledBody => Simulator.ControlledBody;
+
+ public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledAdjointBody => Simulator.ControlledAdjointBody;
+ }
+
+ public class Type2SimulatorM : M
+ {
+ private QuantumSimulator.QSimM Simulator { get; }
+
+ public Type2SimulatorM(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimM(m);
+ }
+
+ public override Func Body => Simulator.Body;
+ }
+
+ public class Type2SimulatorApplyIsingXX : IsingXX
+ {
+ private QuantumSimulator.QSimExp Simulator { get; }
+
+ public Type2SimulatorApplyIsingXX(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimExp(m);
+ }
+
+ public override Func<(double, Qubit, Qubit), QVoid> Body => (args) =>
+ {
+ (double theta, Qubit q1, Qubit q2) = (args);
+ Simulator.Body(((new QArray(Pauli.PauliX, Pauli.PauliX)), (theta * 2.0), (new QArray(q1, q2))));
+ return QVoid.Instance;
+ };
+
+ public override Func<(IQArray, (double, Qubit, Qubit)), QVoid> ControlledBody => (args) =>
+ {
+ (IQArray ctrls, (double theta, Qubit q1, Qubit q2)) = args;
+
+ if ((ctrls == null) || (ctrls.Count == 0))
+ {
+ Body((theta, q1, q2));
+ }
+ else
+ {
+ Simulator.ControlledBody((ctrls, ((new QArray(Pauli.PauliX, Pauli.PauliX)), (theta * 2.0), (new QArray(q1, q2)))));
+ }
+
+ return QVoid.Instance;
+ };
+ }
+
+ public class Type2SimulatorApplyIsingYY : IsingYY
+ {
+ private QuantumSimulator.QSimExp Simulator { get; }
+
+ public Type2SimulatorApplyIsingYY(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimExp(m);
+ }
+
+ public override Func<(double, Qubit, Qubit), QVoid> Body => (args) =>
+ {
+ (double theta, Qubit q1, Qubit q2) = (args);
+ Simulator.Body(((new QArray(Pauli.PauliY, Pauli.PauliY)), (theta * 2.0), (new QArray(q1, q2))));
+ return QVoid.Instance;
+ };
+
+ public override Func<(IQArray, (double, Qubit, Qubit)), QVoid> ControlledBody => (args) =>
+ {
+ (IQArray ctrls, (double theta, Qubit q1, Qubit q2)) = args;
+
+ if ((ctrls == null) || (ctrls.Count == 0))
+ {
+ Body((theta, q1, q2));
+ }
+ else
+ {
+ Simulator.ControlledBody((ctrls, ((new QArray(Pauli.PauliY, Pauli.PauliY)), (theta * 2.0), (new QArray(q1, q2)))));
+ }
+
+ return QVoid.Instance;
+ };
+ }
+ public class Type2SimulatorApplyIsingZZ : IsingZZ
+ {
+ private QuantumSimulator.QSimExp Simulator { get; }
+
+ public Type2SimulatorApplyIsingZZ(QuantumSimulator m) : base(m)
+ {
+ Simulator = new QuantumSimulator.QSimExp(m);
+ }
+
+ public override Func<(double, Qubit, Qubit), QVoid> Body => (args) =>
+ {
+ (double theta, Qubit q1, Qubit q2) = (args);
+ Simulator.Body(((new QArray(Pauli.PauliZ, Pauli.PauliZ)), (theta * 2.0), (new QArray(q1, q2))));
+ return QVoid.Instance;
+ };
+
+ public override Func<(IQArray, (double, Qubit, Qubit)), QVoid> ControlledBody => (args) =>
+ {
+ (IQArray ctrls, (double theta, Qubit q1, Qubit q2)) = args;
+
+ if ((ctrls == null) || (ctrls.Count == 0))
+ {
+ Body((theta, q1, q2));
+ }
+ else
+ {
+ Simulator.ControlledBody((ctrls, ((new QArray(Pauli.PauliZ, Pauli.PauliZ)), (theta * 2.0), (new QArray(q1, q2)))));
+ }
+
+ return QVoid.Instance;
+ };
+ }
+ }
+}
diff --git a/src/Simulation/DecompositionsCore/Common/CircuitUtilities.qs b/src/Simulation/DecompositionsCore/Common/CircuitUtilities.qs
new file mode 100644
index 00000000000..38654852ad9
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Common/CircuitUtilities.qs
@@ -0,0 +1,137 @@
+namespace Microsoft.Quantum.Intrinsic {
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+ open Microsoft.Quantum.Diagnostics;
+
+ /// Applies a unitary operation such that
+ /// `SpreadZ(...); Exp([PauliZ],theta,[from]) ; Adjoint SpreadZ(...);` is equivalent to `Exp([PauliZ,..,PauliZ],theta,[from] + to)`
+ @EnableTestingViaName("Test.Decompositions.SpreadZ")
+ internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj {
+ if (Length(to) > 0) {
+ CNOT(to[0], from);
+ if (Length(to) > 1) {
+ let half = Length(to) / 2;
+ SpreadZ(to[0], to[half + 1 .. Length(to) - 1]);
+ SpreadZ(from, to[1 .. half]);
+ }
+ }
+ }
+
+ /// Applies a unitary operation such that
+ /// `MapPauli(...); R(from,...) ; Adjoint MapPauli(...);` is equivalent to `R(to,...)`
+ @EnableTestingViaName("Test.Decompositions.MapPauli")
+ internal operation MapPauli(qubit : Qubit, from : Pauli, to : Pauli) : Unit is Adj {
+ if (from == to) {
+ }
+ elif ((from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ)) {
+ H(qubit);
+ }
+ elif (from == PauliZ and to == PauliY) {
+ H(qubit);
+ S(qubit);
+ H(qubit);
+ }
+ elif (from == PauliY and to == PauliZ) {
+ H(qubit);
+ Adjoint S(qubit);
+ H(qubit);
+ }
+ elif (from == PauliY and to == PauliX) {
+ S(qubit);
+ }
+ elif (from == PauliX and to == PauliY) {
+ Adjoint S(qubit);
+ }
+ else {
+ fail "Unsupported input";
+ }
+ }
+
+ /// Given a multiply-controlled operation that requires k controls
+ /// applies it using ceiling(k/2) controls and using floor(k/2) temporary qubits
+ /// almostCCX(c1,c2,t); U(c1,c2) must be equivalent to CCX(c1,c2,t) for some two-qubit unitary operation U(c1,c2) given target qubit starts
+ /// in zero state, ( for Adjoint it is asserted that target qubit is returned to zero state)
+ @EnableTestingViaName("Test.Decompositions.ApplyWithLessControlsA")
+ internal operation ApplyWithLessControlsA<'T>(op : ((Qubit[],'T) => Unit is Adj), (controls : Qubit[], arg : 'T), almostCCX : ((Qubit,Qubit,Qubit) => Unit is Adj)) : Unit is Adj {
+ let numControls = Length(controls);
+ let numControlPairs = numControls / 2;
+ using (temps = Qubit[numControlPairs]) {
+ within {
+ for (numPair in 0 .. numControlPairs - 1) { // constant depth
+ almostCCX(controls[2*numPair], controls[2*numPair + 1], temps[numPair]);
+ }
+ } apply {
+ let newControls = numControls % 2 == 0 ? temps | temps + [controls[numControls - 1]];
+ op(newControls, arg);
+ }
+ }
+ }
+
+ /// almostCCX(c1,c2,t); U(c1,c2) must be equivalent to CCX(c1,c2,t) for some two-qubit unitary operation U(c1,c2) given target qubit starts
+ /// in zero state, ( for Adjoint it is asserted that target qubit is returned to zero state)
+ @EnableTestingViaName("Test.Decompositions.ApplyUsingSinglyControlledVersion")
+ internal operation ApplyUsingSinglyControlledVersion<'T>(op : ('T => Unit is Adj), controlledOp : ((Qubit,'T) => Unit is Adj), arg : 'T , almostCCX : ((Qubit,Qubit,Qubit) => Unit is Adj)) : Unit is Adj + Ctl {
+ body(...) {
+ op(arg);
+ }
+ controlled(ctrls, ...) {
+ let numControls = Length(ctrls);
+ if (numControls == 0) { op(arg); }
+ elif (numControls == 1) { controlledOp(ctrls[0], arg); }
+ else {
+ let inner = ApplyUsingSinglyControlledVersion(op, controlledOp, _, almostCCX);
+ ApplyWithLessControlsA(Controlled inner, (ctrls, arg), almostCCX);
+ }
+ }
+ }
+
+ @EnableTestingViaName("Test.Decompositions.DispatchR1Frac")
+ internal operation DispatchR1Frac(numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl {
+ if (power >= 0 ) { // when power is negative the operations is (1,exp(i pi*2^|n|*k)) and exp(i pi*2^|n|*k) = 1
+ let (kModPositive,n) = Utils.ReducedDyadicFractionPeriodic(numerator,power); // k is odd, or (k,n) are both 0
+ if (n == 0) { // kModPositive is 0,1
+ if (kModPositive == 1) { Z(qubit); }
+ elif (kModPositive == 0) {}
+ else { fail "Something went wrong. This should be unreachable"; }
+ }
+ elif (n == 1) { // period is 4, kModPositive is 1,3
+ if (kModPositive == 1) { S(qubit); }
+ elif (kModPositive == 3) { Adjoint S(qubit); }
+ else { fail "Something went wrong. This should be unreachable"; }
+ }
+ elif (n == 2) { // period is 8, kModPositive is 1,3,5,7
+ if (kModPositive == 1) { T(qubit); }
+ elif (kModPositive == 3) { TS(qubit); }
+ elif (kModPositive == 5) { Adjoint TS(qubit); }
+ elif (kModPositive == 7) { Adjoint T(qubit); }
+ else { fail "Something went wrong. This should be unreachable"; }
+ }
+ else {
+ let phi = Utils.DyadicFractionAsDouble(kModPositive, n);
+ R1(phi,qubit);
+ }
+ }
+ }
+
+ @EnableTestingViaName("Test.Decompositions.ApplyGlobalPhaseWithR1")
+ internal operation ApplyGlobalPhaseWithR1(theta : Double) : Unit is Adj + Ctl {
+ body(...) {}
+ controlled(ctrls, ... ) {
+ let numControls = Length(ctrls);
+ if (numControls > 0) {
+ Controlled R1(ctrls[1 .. numControls - 1], (theta, ctrls[0]));
+ }
+ }
+ }
+
+ @EnableTestingViaName("Test.Decompositions.ApplyGlobalPhaseFracWithR1Frac")
+ internal operation ApplyGlobalPhaseFracWithR1Frac(numerator : Int, power : Int) : Unit is Adj + Ctl {
+ body(...) {}
+ controlled(ctrls, ... ) {
+ let numControls = Length(ctrls);
+ if (numControls > 0 ) {
+ Controlled R1Frac(ctrls[1 .. numControls - 1], (numerator, power, ctrls[0]));
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore/Type2/Microsoft.Quantum.Decompositions.Core.Type2.csproj b/src/Simulation/DecompositionsCore/Type2/Microsoft.Quantum.Decompositions.Core.Type2.csproj
new file mode 100644
index 00000000000..de72236cf51
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Type2/Microsoft.Quantum.Decompositions.Core.Type2.csproj
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ netstandard2.1
+ true
+ false
+ false
+
+
+
+ Microsoft
+ Support for Type 2 Q# circuit decompositions.
+ See: https://docs.microsoft.com/en-us/quantum/relnotes/
+ MIT
+ https://github.com/microsoft/qsharp-runtime
+ https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png
+ Quantum Q# Qsharp Decompositions
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Simulation/DecompositionsCore/Type2/Type2-Decompositions.qs b/src/Simulation/DecompositionsCore/Type2/Type2-Decompositions.qs
new file mode 100644
index 00000000000..6ab982c5b67
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Type2/Type2-Decompositions.qs
@@ -0,0 +1,509 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Quantum.Intrinsic {
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+ open Microsoft.Quantum.Diagnostics;
+
+ /// # Summary
+ /// Performs the identity operation (no-op) on a single qubit.
+ ///
+ /// # Remarks
+ /// This is a no-op. It is provided for completeness and because
+ /// sometimes it is useful to call the identity in an algorithm or to pass it as a parameter.
+ @EnableTestingViaName("Test.Decompositions.I")
+ operation I(target : Qubit) : Unit
+ is Adj + Ctl {
+ body (...) { }
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies a rotation about the $x$-axis by a given angle.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_x(\theta) \mathrel{:=}
+ /// e^{-i \theta \sigma_x / 2} =
+ /// \begin{bmatrix}
+ /// \cos \frac{\theta}{2} & -i\sin \frac{\theta}{2} \\\\
+ /// -i\sin \frac{\theta}{2} & \cos \frac{\theta}{2}
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## theta
+ /// Angle about which the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// R(PauliX, theta, qubit);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.Rx")
+ operation Rx(theta : Double, qubit : Qubit) : Unit is Ctl + Adj {
+ body(...) {
+ R(PauliX, theta, qubit);
+ }
+ adjoint(...) {
+ R(PauliX, -theta, qubit);
+ }
+ }
+
+ /// # Summary
+ /// Applies a rotation about the $y$-axis by a given angle.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_y(\theta) \mathrel{:=}
+ /// e^{-i \theta \sigma_y / 2} =
+ /// \begin{bmatrix}
+ /// \cos \frac{\theta}{2} & -\sin \frac{\theta}{2} \\\\
+ /// \sin \frac{\theta}{2} & \cos \frac{\theta}{2}
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## theta
+ /// Angle about which the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// R(PauliY, theta, qubit);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.Ry")
+ operation Ry(theta : Double, qubit : Qubit) : Unit is Ctl + Adj {
+ body(...) {
+ R(PauliY, theta, qubit);
+ }
+ adjoint(...) {
+ R(PauliY, -theta, qubit);
+ }
+ }
+
+ /// # Summary
+ /// Applies a rotation about the $z$-axis by a given angle.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_z(\theta) \mathrel{:=}
+ /// e^{-i \theta \sigma_z / 2} =
+ /// \begin{bmatrix}
+ /// e^{-i \theta / 2} & 0 \\\\
+ /// 0 & e^{i \theta / 2}
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## theta
+ /// Angle about which the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// R(PauliZ, theta, qubit);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.Rz")
+ operation Rz(theta : Double, qubit : Qubit) : Unit is Ctl + Adj {
+ body(...) {
+ R(PauliZ, theta, qubit);
+ }
+ adjoint(...) {
+ R(PauliZ, -theta, qubit);
+ }
+ }
+
+ /// # Summary
+ /// Applies the controlled-NOT (CNOT) gate to a pair of qubits.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// \operatorname{CNOT} \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 1 & 0 & 0 & 0 \\\\
+ /// 0 & 1 & 0 & 0 \\\\
+ /// 0 & 0 & 0 & 1 \\\\
+ /// 0 & 0 & 1 & 0
+ /// \end{bmatrix},
+ /// \end{align}
+ ///
+ /// where rows and columns are ordered as in the quantum concepts guide.
+ ///
+ /// # Input
+ /// ## control
+ /// Control qubit for the CNOT gate.
+ /// ## target
+ /// Target qubit for the CNOT gate.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// Controlled X([control], target);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.CNOT")
+ operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl {
+ body (...) {
+ Controlled X([control], target);
+ }
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies the doubly controlled–NOT (CCNOT) gate to three qubits.
+ ///
+ /// # Input
+ /// ## control1
+ /// First control qubit for the CCNOT gate.
+ /// ## control2
+ /// Second control qubit for the CCNOT gate.
+ /// ## target
+ /// Target qubit for the CCNOT gate.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// Controlled X([control1, control2], target);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.CCNOT")
+ operation CCNOT(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj + Ctl {
+ body (...) {
+ Controlled X([control1, control2], target);
+ }
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies a rotation about the $\ket{1}$ state by a given angle.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_1(\theta) \mathrel{:=}
+ /// \operatorname{diag}(1, e^{i\theta}).
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## theta
+ /// Angle about which the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ ///
+ /// # Remarks
+ /// Equivalent to:
+ /// ```qsharp
+ /// R(PauliZ, theta, qubit);
+ /// R(PauliI, -theta, qubit);
+ /// ```
+ @EnableTestingViaName("Test.Decompositions.R1")
+ operation R1(theta : Double, qubit : Qubit) : Unit is Adj + Ctl {
+ body(...) {
+ ApplyGlobalPhase( theta / 2.0 );
+ Rz(theta, qubit);
+ }
+ adjoint(...) {
+ R1(-theta, qubit);
+ }
+ }
+
+ /// # Summary
+ /// Given an array of qubits, measure them and ensure they are in the |0⟩ state
+ /// such that they can be safely released.
+ ///
+ /// # Input
+ /// ## qubits
+ /// An array of qubits whose states are to be reset to $\ket{0}$.
+ @EnableTestingViaName("Test.Decompositions.ResetAll")
+ operation ResetAll(qubits : Qubit[]) : Unit {
+ for (qubit in qubits) {
+ Reset(qubit);
+ }
+ }
+
+ /// # Summary
+ /// Applies the exponential of a multi-qubit Pauli operator.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// e^{i \theta [P_0 \otimes P_1 \cdots P_{N-1}]},
+ /// \end{align}
+ /// where $P_i$ is the $i$th element of `paulis`, and where
+ /// $N = $`Length(paulis)`.
+ ///
+ /// # Input
+ /// ## paulis
+ /// Array of single-qubit Pauli values indicating the tensor product
+ /// factors on each qubit.
+ /// ## theta
+ /// Angle about the given multi-qubit Pauli operator by which the
+ /// target register is to be rotated.
+ /// ## qubits
+ /// Register to apply the given rotation to.
+ @EnableTestingViaName("Test.Decompositions.Exp")
+ operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
+ body(...) {
+ if (Length(paulis) != Length(qubits)) { fail "Arrays 'pauli' and 'target' must have the same length"; }
+ let (newPaulis, newQubits) = Utils.RemovePauliI(paulis, qubits);
+
+ if (Length(newPaulis) != 0) {
+ if (Length(newPaulis) == 2 and newPaulis[0] != newPaulis[1]) { fail $"Type 2 Decompositions support only rotation around XX, YY, ZZ given {paulis}"; }
+ ExpNoIdUtil(newPaulis, theta , newQubits, R(_, -2.0 * theta, _));
+ }
+ else {
+ ApplyGlobalPhase(theta);
+ }
+ }
+ adjoint(...) {
+ Exp(paulis, -theta, qubits);
+ }
+ }
+
+ /// # Summary
+ /// Applies a rotation about the $\ket{1}$ state by an angle specified
+ /// as a dyadic fraction.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_1(n, k) \mathrel{:=}
+ /// \operatorname{diag}(1, e^{i \pi k / 2^n}).
+ /// \end{align}
+ ///
+ /// > [!WARNING]
+ /// > This operation uses the **opposite** sign convention from
+ /// > @"microsoft.quantum.intrinsic.r", and does not include the
+ /// > factor of $1/ 2$ included by @"microsoft.quantum.intrinsic.r1".
+ ///
+ /// # Input
+ /// ## numerator
+ /// Numerator in the dyadic fraction representation of the angle
+ /// by which the qubit is to be rotated.
+ /// ## power
+ /// Power of two specifying the denominator of the angle by which
+ /// the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.R1Frac")
+ operation R1Frac(numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl {
+ DispatchR1Frac(numerator, power, qubit);
+ }
+
+ /// # Summary
+ /// Applies a rotation about the given Pauli axis by an angle specified
+ /// as a dyadic fraction.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_{\mu}(n, k) \mathrel{:=}
+ /// e^{i \pi n \sigma_{\mu} / 2^k},
+ /// \end{align}
+ /// where $\mu \in \{I, X, Y, Z\}$.
+ ///
+ /// > [!WARNING]
+ /// > This operation uses the **opposite** sign convention from
+ /// > @"microsoft.quantum.intrinsic.r".
+ ///
+ /// # Input
+ /// ## pauli
+ /// Pauli operator to be exponentiated to form the rotation.
+ /// ## numerator
+ /// Numerator in the dyadic fraction representation of the angle
+ /// by which the qubit is to be rotated.
+ /// ## power
+ /// Power of two specifying the denominator of the angle by which
+ /// the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.RFrac")
+ operation RFrac(pauli : Pauli, numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl {
+ if (pauli == PauliI) {
+ ApplyGlobalPhaseFracWithR1Frac(numerator, power);
+ }
+ else {
+ if (power >= 0) { // when power is negative the operation is exp(i P pi*2^|n|*k) = I
+
+ within {
+ MapPauli(qubit, PauliZ, pauli);
+ }
+ apply {
+ ApplyGlobalPhaseFracWithR1Frac(numerator, power);
+ R1Frac(-numerator, power - 1, qubit);
+ }
+
+ //Below is another option for implementing RFrac
+ //let (kModPositive,n) = Utils.ReducedDyadicFractionPeriodic(numerator,power); // k is odd, in the range [1,2*2^n-1] or (k,n) are both 0
+ //let numeratorD = Microsoft.Quantum.Math.PI() * Microsoft.Quantum.Convert.IntAsDouble(kModPositive);
+ //let phi = numeratorD * Microsoft.Quantum.Math.PowD(2.0, Microsoft.Quantum.Convert.IntAsDouble(-n));
+ //R(pauli, -2.0 * phi, qubit);
+
+ }
+ }
+ }
+
+ /// # Summary
+ /// Applies the exponential of a multi-qubit Pauli operator
+ /// with an argument given by a dyadic fraction.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// e^{i \pi k [P_0 \otimes P_1 \cdots P_{N-1}] / 2^n},
+ /// \end{align}
+ /// where $P_i$ is the $i$th element of `paulis`, and where
+ /// $N = $`Length(paulis)`.
+ ///
+ /// # Input
+ /// ## paulis
+ /// Array of single-qubit Pauli values indicating the tensor product
+ /// factors on each qubit.
+ /// ## numerator
+ /// Numerator ($k$) in the dyadic fraction representation of the angle
+ /// by which the qubit register is to be rotated.
+ /// ## power
+ /// Power of two ($n$) specifying the denominator of the angle by which
+ /// the qubit register is to be rotated.
+ /// ## qubits
+ /// Register to apply the given rotation to.
+ @EnableTestingViaName("Test.Decompositions.ExpFrac")
+ operation ExpFrac(paulis : Pauli[], numerator : Int, power : Int, qubits : Qubit[]) : Unit is Adj + Ctl {
+ body(...) {
+ if (Length(paulis) != Length(qubits)) { fail "Arrays 'pauli' and 'target' must have the same length"; }
+
+ if (Length(paulis) != 0) {
+ let indices = Utils.IndicesOfNonIdentity(paulis);
+ let newPaulis = Utils.ArrayFromIndiciesP(paulis, indices);
+ let newQubits = Utils.ArrayFromIndiciesQ(qubits, indices);
+
+ if (Length(indices) != 0) {
+ let (kModPositive,n) = Utils.ReducedDyadicFractionPeriodic(numerator, power); // k is odd, in the range [1,2*2^n-1] or (k,n) are both 0
+ let numeratorD = Microsoft.Quantum.Math.PI() * Microsoft.Quantum.Convert.IntAsDouble(kModPositive);
+ let theta = numeratorD * Microsoft.Quantum.Math.PowD(2.0, Microsoft.Quantum.Convert.IntAsDouble(-n));
+ ExpNoIdUtil(newPaulis, theta, newQubits, RFrac(_, numerator, power, _));
+ }
+ else {
+ ApplyGlobalPhaseFracWithR1Frac(numerator, power);
+ }
+ }
+ }
+ adjoint(...) {
+ ExpFrac(paulis, -numerator, power, qubits);
+ }
+ }
+
+ /// # Summary
+ /// Performs a joint measurement of one or more qubits in the
+ /// specified Pauli bases.
+ ///
+ /// # Description
+ /// The output result is given by the distribution:
+ /// \begin{align}
+ /// \Pr(\texttt{Zero} | \ket{\psi}) =
+ /// \frac12 \braket{
+ /// \psi \mid|
+ /// \left(
+ /// \boldone + P_0 \otimes P_1 \otimes \cdots \otimes P_{N-1}
+ /// \right) \mid|
+ /// \psi
+ /// },
+ /// \end{align}
+ /// where $P_i$ is the $i$th element of `bases`, and where
+ /// $N = \texttt{Length}(\texttt{bases})$.
+ /// That is, measurement returns a `Result` $d$ such that the eigenvalue of the
+ /// observed measurement effect is $(-1)^d$.
+ ///
+ /// # Input
+ /// ## bases
+ /// Array of single-qubit Pauli values indicating the tensor product
+ /// factors on each qubit.
+ /// ## qubits
+ /// Register of qubits to be measured.
+ ///
+ /// # Output
+ /// `Zero` if the $+1$ eigenvalue is observed, and `One` if
+ /// the $-1$ eigenvalue is observed.
+ ///
+ /// # Remarks
+ /// If the basis array and qubit array are different lengths, then the
+ /// operation will fail.
+ @EnableTestingViaName("Test.Decompositions.Measure")
+ operation Measure(bases : Pauli[], qubits : Qubit[]) : Result {
+ if (Length(bases) == 1) {
+ MapPauli(qubits[0], PauliZ, bases[0]);
+ return M(qubits[0]);
+ }
+ else {
+ using (q = Qubit()) {
+ within {
+ H(q);
+ }
+ apply {
+ for (k in 0 .. Length(bases) - 1) {
+ if (bases[k] == PauliX) { Controlled X([qubits[k]], q); }
+ if (bases[k] == PauliZ) { Controlled Z([qubits[k]], q); }
+ if (bases[k] == PauliY) { Controlled Y([qubits[k]], q); }
+ }
+ }
+ return M(q);
+ }
+ }
+ }
+
+ /// # Summary
+ /// Measures a single qubit in the Z basis.
+ ///
+ /// # Description
+ /// Performs a single-qubit measurement in the $Z$-basis.
+ ///
+ /// # Input
+ /// ## target
+ /// A single qubit to be measured.
+ ///
+ /// # Output
+ /// The result of measuring `target` in the Pauli $Z$ basis.
+ operation MResetZ (target : Qubit) : Result {
+ let r = M(target);
+ Reset(target);
+ return r;
+ }
+
+
+ /// # Summary
+ /// Measures a single qubit in the X basis.
+ ///
+ /// # Description
+ /// Performs a single-qubit measurement in the $X$-basis.
+ ///
+ /// # Input
+ /// ## target
+ /// A single qubit to be measured.
+ ///
+ /// # Output
+ /// The result of measuring `target` in the Pauli $X$ basis.
+ operation MResetX (target : Qubit) : Result {
+ let r = Measure([PauliX], [target]);
+ Reset(target);
+ return r;
+ }
+
+
+ /// # Summary
+ /// Measures a single qubit in the Y basis.
+ ///
+ /// # Description
+ /// Performs a single-qubit measurement in the $Y$-basis.
+ ///
+ /// # Input
+ /// ## target
+ /// A single qubit to be measured.
+ ///
+ /// # Output
+ /// The result of measuring `target` in the Pauli $Y$ basis.
+ operation MResetY (target : Qubit) : Result {
+ let r = Measure([PauliY], [target]);
+ Reset(target);
+ return r;
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore/Type2/Type2-Internals.qs b/src/Simulation/DecompositionsCore/Type2/Type2-Internals.qs
new file mode 100644
index 00000000000..ebfc9d2a7c1
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Type2/Type2-Internals.qs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Quantum.Intrinsic {
+ open Microsoft.Quantum.Decompositions.Utilities as Utils;
+ open Microsoft.Quantum.Diagnostics;
+
+ @EnableTestingViaName("Test.Decompositions.ApplyGlobalPhase")
+ internal operation ApplyGlobalPhase(theta : Double) : Unit is Ctl + Adj {
+ body(...) {}
+ controlled(controls, (...)) {
+ if (Length(controls) > 0) {
+ let qubit = controls[0]; //Microsoft.Quantum.Arrays.Head(controls);
+ let rest = controls[1...]; //Microsoft.Quantum.Arrays.Rest(controls);
+ // Invoke Controlled R1, which will recursively call back into ApplyGlobalPhase.
+ // Each time the controls is one shorter, until it is empty and the recursion stops.
+ Controlled R1(rest, (theta, qubit));
+ }
+ }
+ }
+
+ @EnableTestingViaName("Test.Decompositions.TS")
+ internal operation TS(target : Qubit) : Unit is Adj + Ctl {
+ T(target);
+ S(target);
+ }
+
+ @EnableTestingViaName("Test.Decompositions.ExpNoIdUtil")
+ internal operation ExpNoIdUtil(paulis : Pauli[], theta : Double, qubits : Qubit[], rotation : ((Pauli, Qubit) => Unit is Adj + Ctl)) : Unit is Ctl {
+ if (Length(paulis) != Length(qubits)) { fail "Arrays 'paulis' and 'qubits' must have the same length"; }
+ if (Length(paulis) == 1) {
+ rotation(paulis[0], qubits[0]);
+ }
+ elif (Length(paulis) == 2) {
+ within {
+ MapPauli(qubits[1], paulis[0], paulis[1]);
+ }
+ apply {
+ if (paulis[0] == PauliX) {
+ IsingXX(theta / 2.0, qubits[0], qubits[1]);
+ } elif (paulis[0] == PauliY) {
+ IsingYY(theta / 2.0, qubits[0], qubits[1]);
+ } elif (paulis[0] == PauliZ) {
+ IsingZZ(theta / 2.0, qubits[0], qubits[1]);
+ } else {
+ fail "Type2 decompositions do not support PauliI";
+ }
+ }
+ }
+ else { // Length(paulis) > 2
+ within {
+ for (i in 0 .. Length(paulis) - 1) {
+ MapPauli(qubits[i], PauliZ, paulis[i]);
+ }
+ }
+ apply {
+ within {
+ SpreadZ(qubits[1], qubits[2 .. Length(qubits) - 1]);
+ }
+ apply {
+ ExpNoIdUtil([PauliZ,PauliZ], theta, [qubits[0], qubits[1]], rotation);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/Simulation/DecompositionsCore/Type2/Type2-Intrinsic.qs b/src/Simulation/DecompositionsCore/Type2/Type2-Intrinsic.qs
new file mode 100644
index 00000000000..b65b85ddbd3
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Type2/Type2-Intrinsic.qs
@@ -0,0 +1,271 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Quantum.Intrinsic {
+ open Microsoft.Quantum.Diagnostics;
+
+ /// # Summary
+ /// Applies the Pauli $X$ gate.
+ ///
+ /// \begin{align}
+ /// \sigma_x \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 0 & 1 \\\\
+ /// 1 & 0
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.X")
+ operation X(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies the Pauli $Y$ gate.
+ ///
+ /// \begin{align}
+ /// \sigma_y \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 0 & -i \\\\
+ /// i & 0
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.Y")
+ operation Y(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies the Pauli $Z$ gate.
+ ///
+ /// \begin{align}
+ /// \sigma_z \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 1 & 0 \\\\
+ /// 0 & -1
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.Z")
+ operation Z(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies the Hadamard transformation to a single qubit.
+ ///
+ /// \begin{align}
+ /// H \mathrel{:=}
+ /// \frac{1}{\sqrt{2}}
+ /// \begin{bmatrix}
+ /// 1 & 1 \\\\
+ /// 1 & -1
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.H")
+ operation H(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies the π/4 phase gate to a single qubit.
+ ///
+ /// \begin{align}
+ /// S \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 1 & 0 \\\\
+ /// 0 & i
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.S")
+ operation S(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Applies the π/8 gate to a single qubit.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// T \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 1 & 0 \\\\
+ /// 0 & e^{i \pi / 4}
+ /// \end{bmatrix}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ @EnableTestingViaName("Test.Decompositions.T")
+ operation T(qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Applies the SWAP gate to a pair of qubits.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// \operatorname{SWAP} \mathrel{:=}
+ /// \begin{bmatrix}
+ /// 1 & 0 & 0 & 0 \\\\
+ /// 0 & 0 & 1 & 0 \\\\
+ /// 0 & 1 & 0 & 0 \\\\
+ /// 0 & 0 & 0 & 1
+ /// \end{bmatrix},
+ /// \end{align}
+ ///
+ /// where rows and columns are ordered as in the quantum concepts guide.
+ ///
+ /// # Input
+ /// ## qubit1
+ /// First qubit to be swapped.
+ /// ## qubit2
+ /// Second qubit to be swapped.
+ @EnableTestingViaName("Test.Decompositions.SWAP")
+ operation SWAP(qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ adjoint self;
+ }
+
+ /// # Summary
+ /// Applies a rotation about the given Pauli axis.
+ ///
+ /// # Description
+ /// \begin{align}
+ /// R_{\mu}(\theta) \mathrel{:=}
+ /// e^{-i \theta \sigma_{\mu} / 2},
+ /// \end{align}
+ /// where $\mu \in \{I, X, Y, Z\}$.
+ ///
+ /// # Input
+ /// ## pauli
+ /// Pauli operator ($\mu$) to be exponentiated to form the rotation.
+ /// ## theta
+ /// Angle about which the qubit is to be rotated.
+ /// ## qubit
+ /// Qubit to which the gate should be applied.
+ ///
+ /// # Remarks
+ /// When called with `pauli = PauliI`, this operation applies
+ /// a *global phase*. This phase can be significant
+ /// when used with the `Controlled` functor.
+ @EnableTestingViaName("Test.Decompositions.R")
+ operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Performs a measurement of a single qubit in the
+ /// Pauli $Z$ basis.
+ ///
+ /// # Description
+ /// The output result is given by
+ /// the distribution
+ /// \begin{align}
+ /// \Pr(\texttt{Zero} | \ket{\psi}) =
+ /// \braket{\psi | 0} \braket{0 | \psi}.
+ /// \end{align}
+ ///
+ /// # Input
+ /// ## qubit
+ /// Qubit to be measured.
+ ///
+ /// # Output
+ /// `Zero` if the $+1$ eigenvalue is observed, and `One` if
+ /// the $-1$ eigenvalue is observed.
+ @EnableTestingViaName("Test.Decompositions.M")
+ operation M(qubit : Qubit) : Result {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Given a single qubit, measures it and ensures it is in the |0⟩ state
+ /// such that it can be safely released.
+ ///
+ /// # Input
+ /// ## qubit
+ /// The qubit whose state is to be reset to $\ket{0}$.
+ @EnableTestingViaName("Test.Decompositions.Reset")
+ operation Reset(qubit : Qubit) : Unit {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Applies the Ising $XX$ gate.
+ ///
+ /// TODO - describe XX gate.
+ ///
+ /// # Input
+ /// ## theta
+ /// The angle about which the qubits are rotated.
+ /// ## qubit0
+ /// The first qubit input to the gate.
+ /// ## qubit1
+ /// The second qubit input to the gate.
+ /// NOTE: If made public, consider a more concise name to match other quantum gate equivalent operations.
+ @EnableTestingViaName("Test.Decompositions.IsingXX")
+ operation IsingXX(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Ctl {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Applies the Ising $YY$ gate.
+ ///
+ /// TODO - describe YY gate.
+ ///
+ /// # Input
+ /// ## theta
+ /// The angle about which the qubits are rotated.
+ /// ## qubit0
+ /// The first qubit input to the gate.
+ /// ## qubit1
+ /// The second qubit input to the gate.
+ /// NOTE: If made public, consider a more concise name to match other quantum gate equivalent operations.
+ @EnableTestingViaName("Test.Decompositions.IsingYY")
+ operation IsingYY(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Ctl {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Applies the Ising $ZZ$ gate.
+ ///
+ /// TODO - describe ZZ gate.
+ ///
+ /// # Input
+ /// ## theta
+ /// The angle about which the qubits are rotated.
+ /// ## qubit0
+ /// The first qubit input to the gate.
+ /// ## qubit1
+ /// The second qubit input to the gate.
+ /// NOTE: If made public, consider a more concise name to match other quantum gate equivalent operations.
+ @EnableTestingViaName("Test.Decompositions.IsingZZ")
+ operation IsingZZ(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Ctl {
+ body intrinsic;
+ }
+
+}
\ No newline at end of file
diff --git a/src/Simulation/DecompositionsCore/Utilities/Microsoft.Quantum.Decompositions.Utilities.csproj b/src/Simulation/DecompositionsCore/Utilities/Microsoft.Quantum.Decompositions.Utilities.csproj
new file mode 100644
index 00000000000..7be8560156f
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Utilities/Microsoft.Quantum.Decompositions.Utilities.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netstandard2.1
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Simulation/DecompositionsCore/Utilities/Utilities.qs b/src/Simulation/DecompositionsCore/Utilities/Utilities.qs
new file mode 100644
index 00000000000..708e23b3f4f
--- /dev/null
+++ b/src/Simulation/DecompositionsCore/Utilities/Utilities.qs
@@ -0,0 +1,71 @@
+namespace Microsoft.Quantum.Decompositions.Utilities {
+
+ function ArrayFromIndiciesP(values : Pauli[], indicies : Int[]) : Pauli[] {
+ mutable arr = new Pauli[Length(indicies)];
+ for (i in 0 .. Length(indicies) - 1) {
+ set arr w/= i <- values[indicies[i]];
+ }
+ return arr;
+ }
+
+ function ArrayFromIndiciesQ(values : Qubit[], indicies : Int[]) : Qubit[] {
+ mutable arr = new Qubit[Length(indicies)];
+ for (i in 0 .. Length(indicies) - 1) {
+ set arr w/= i <- values[indicies[i]];
+ }
+ return arr;
+ }
+
+ function IndicesOfNonIdentity(paulies : Pauli[]) : Int[] {
+ mutable nonIdPauliCount = 0;
+
+ for (i in 0 .. Length(paulies) - 1) {
+ if (paulies[i] != PauliI) { set nonIdPauliCount += 1; }
+ }
+
+ mutable indices = new Int[nonIdPauliCount];
+ mutable index = 0;
+
+ for (i in 0 .. Length(paulies) - 1) {
+ if (paulies[i] != PauliI) {
+ set indices w/= index <- i;
+ set index = index + 1;
+ }
+ }
+
+ return indices;
+ }
+
+ function ReducedDyadicFraction(numerator : Int, denominatorPowerOfTwo : Int) : (Int,Int) {
+ if (numerator == 0) { return (0,0); }
+ mutable num = numerator;
+ mutable denPow = denominatorPowerOfTwo;
+ while(num % 2 == 0) {
+ set num /= 2;
+ set denPow += 1;
+ }
+ return (num,denPow);
+ }
+
+ function ReducedDyadicFractionPeriodic(numerator : Int, denominatorPowerOfTwo : Int) : (Int,Int) {
+ let (k,n) = ReducedDyadicFraction(numerator,denominatorPowerOfTwo); // k is odd, or (k,n) are both 0
+ let period = 2*2^n; // \pi k / 2^n is 2\pi periodic, therefore k is 2 * 2^n periodic
+ let kMod = k % period; // if k was negative, we get kMod in a range [-period + 1, 0]
+ let kModPositive = kMod >= 0 ? kMod | kMod + period; // kModPositive is in the range [0, period - 1]
+ return (kModPositive, n);
+ }
+
+ /// # Summary
+ /// Returns π×numerator/2^(denominatorPowerOfTwo) as Double
+ function DyadicFractionAsDouble(numerator : Int, denominatorPowerOfTwo : Int) : Double {
+ let numeratorD = Microsoft.Quantum.Math.PI() * Microsoft.Quantum.Convert.IntAsDouble(numerator);
+ return numeratorD * Microsoft.Quantum.Math.PowD(2.0, Microsoft.Quantum.Convert.IntAsDouble(-denominatorPowerOfTwo));
+ }
+
+ function RemovePauliI(paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) {
+ let indices = IndicesOfNonIdentity(paulis);
+ let newPaulis = ArrayFromIndiciesP(paulis, indices);
+ let newQubits = ArrayFromIndiciesQ(qubits, indices);
+ return (newPaulis, newQubits);
+ }
+}
diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.fs b/src/Simulation/EntryPointDriver.Tests/Tests.fs
index 808b4b6b607..69d00fc41ca 100644
--- a/src/Simulation/EntryPointDriver.Tests/Tests.fs
+++ b/src/Simulation/EntryPointDriver.Tests/Tests.fs
@@ -96,6 +96,7 @@ let private compileCsharp (sources : string seq) =
"System.Runtime.Extensions"
"System.Runtime.Numerics"
"Microsoft.Quantum.CsharpGeneration.EntryPointDriver"
+ "Microsoft.Quantum.QSharp.Base"
"Microsoft.Quantum.QSharp.Core"
"Microsoft.Quantum.QsDataStructures"
"Microsoft.Quantum.Runtime.Core"
diff --git a/src/Simulation/QsharpBase/Assert.qs b/src/Simulation/QsharpBase/Assert.qs
new file mode 100644
index 00000000000..6f36ade4d6b
--- /dev/null
+++ b/src/Simulation/QsharpBase/Assert.qs
@@ -0,0 +1,68 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Quantum.Intrinsic {
+ /// # Summary
+ /// Asserts that measuring the given qubits in the given Pauli basis will
+ /// always have the given result.
+ ///
+ /// # Input
+ /// ## bases
+ /// A measurement effect to assert the probability of, expressed as a
+ /// multi-qubit Pauli operator.
+ /// ## qubits
+ /// A register on which to make the assertion.
+ /// ## result
+ /// The expected result of `Measure(bases, qubits)`.
+ /// ## msg
+ /// A message to be reported if the assertion fails.
+ ///
+ /// # Remarks
+ /// Note that the Adjoint and Controlled versions of this operation will not
+ /// check the condition.
+ ///
+ /// # See Also
+ /// - AssertProb
+ operation Assert (bases : Pauli[], qubits : Qubit[], result : Result, msg : String) : Unit
+ is Adj + Ctl {
+ body intrinsic;
+ }
+
+
+ /// # Summary
+ /// Asserts that measuring the given qubits in the given Pauli basis will have the given result
+ /// with the given probability, within some tolerance.
+ ///
+ /// # Input
+ /// ## bases
+ /// A measurement effect to assert the probability of, expressed as a
+ /// multi-qubit Pauli operator.
+ /// ## qubits
+ /// A register on which to make the assertion.
+ /// ## result
+ /// An expected result of `Measure(bases, qubits)`.
+ /// ## prob
+ /// The probability with which the given result is expected.
+ /// ## msg
+ /// A message to be reported if the assertion fails.
+ ///
+ /// # Example
+ /// ```qsharp
+ /// using (register = Qubit()) {
+ /// H(register);
+ /// AssertProb([PauliZ], [register], One, 0.5,
+ /// "Measuring in conjugate basis did not give 50/50 results.", 1e-5);
+ /// }
+ /// ```
+ ///
+ /// # Remarks
+ /// Note that the Adjoint and Controlled versions of this operation will not
+ /// check the condition.
+ ///
+ /// # See Also
+ /// - Assert
+ operation AssertProb (bases : Pauli[], qubits : Qubit[], result : Result, prob : Double, msg : String, tol : Double) : Unit
+ is Adj + Ctl {
+ body intrinsic;
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/QsharpCore/Bitwise/Bitwise.cs b/src/Simulation/QsharpBase/Bitwise/Bitwise.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Bitwise/Bitwise.cs
rename to src/Simulation/QsharpBase/Bitwise/Bitwise.cs
diff --git a/src/Simulation/QsharpCore/Bitwise/Bitwise.qs b/src/Simulation/QsharpBase/Bitwise/Bitwise.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Bitwise/Bitwise.qs
rename to src/Simulation/QsharpBase/Bitwise/Bitwise.qs
diff --git a/src/Simulation/QsharpCore/Bitwise/Deprecated.qs b/src/Simulation/QsharpBase/Bitwise/Deprecated.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Bitwise/Deprecated.qs
rename to src/Simulation/QsharpBase/Bitwise/Deprecated.qs
diff --git a/src/Simulation/QsharpCore/Convert/Convert.cs b/src/Simulation/QsharpBase/Convert/Convert.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Convert/Convert.cs
rename to src/Simulation/QsharpBase/Convert/Convert.cs
diff --git a/src/Simulation/QsharpCore/Convert/Convert.qs b/src/Simulation/QsharpBase/Convert/Convert.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Convert/Convert.qs
rename to src/Simulation/QsharpBase/Convert/Convert.qs
diff --git a/src/Simulation/QsharpCore/Convert/Deprecated.qs b/src/Simulation/QsharpBase/Convert/Deprecated.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Convert/Deprecated.qs
rename to src/Simulation/QsharpBase/Convert/Deprecated.qs
diff --git a/src/Simulation/QsharpCore/Core.cs b/src/Simulation/QsharpBase/Core.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Core.cs
rename to src/Simulation/QsharpBase/Core.cs
diff --git a/src/Simulation/QsharpCore/Core.qs b/src/Simulation/QsharpBase/Core.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Core.qs
rename to src/Simulation/QsharpBase/Core.qs
diff --git a/src/Simulation/QsharpCore/Diagnostics/AssertAllZero.qs b/src/Simulation/QsharpBase/Diagnostics/AssertAllZero.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Diagnostics/AssertAllZero.qs
rename to src/Simulation/QsharpBase/Diagnostics/AssertAllZero.qs
diff --git a/src/Simulation/QsharpCore/Diagnostics/AssertQubit.qs b/src/Simulation/QsharpBase/Diagnostics/AssertQubit.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Diagnostics/AssertQubit.qs
rename to src/Simulation/QsharpBase/Diagnostics/AssertQubit.qs
diff --git a/src/Simulation/QsharpCore/Diagnostics/Dump.qs b/src/Simulation/QsharpBase/Diagnostics/Dump.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Diagnostics/Dump.qs
rename to src/Simulation/QsharpBase/Diagnostics/Dump.qs
diff --git a/src/Simulation/QsharpCore/Diagnostics/UnitTests.qs b/src/Simulation/QsharpBase/Diagnostics/UnitTests.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Diagnostics/UnitTests.qs
rename to src/Simulation/QsharpBase/Diagnostics/UnitTests.qs
diff --git a/src/Simulation/QsharpCore/Environment.qs b/src/Simulation/QsharpBase/Environment.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Environment.qs
rename to src/Simulation/QsharpBase/Environment.qs
diff --git a/src/Simulation/QsharpCore/Math/Constants.qs b/src/Simulation/QsharpBase/Math/Constants.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Constants.qs
rename to src/Simulation/QsharpBase/Math/Constants.qs
diff --git a/src/Simulation/QsharpCore/Math/Deprecated.qs b/src/Simulation/QsharpBase/Math/Deprecated.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Deprecated.qs
rename to src/Simulation/QsharpBase/Math/Deprecated.qs
diff --git a/src/Simulation/QsharpCore/Math/Math.cs b/src/Simulation/QsharpBase/Math/Math.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Math.cs
rename to src/Simulation/QsharpBase/Math/Math.cs
diff --git a/src/Simulation/QsharpCore/Math/Math.qs b/src/Simulation/QsharpBase/Math/Math.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Math.qs
rename to src/Simulation/QsharpBase/Math/Math.qs
diff --git a/src/Simulation/QsharpCore/Math/Trig.qs b/src/Simulation/QsharpBase/Math/Trig.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Trig.qs
rename to src/Simulation/QsharpBase/Math/Trig.qs
diff --git a/src/Simulation/QsharpCore/Math/Types.qs b/src/Simulation/QsharpBase/Math/Types.qs
similarity index 100%
rename from src/Simulation/QsharpCore/Math/Types.qs
rename to src/Simulation/QsharpBase/Math/Types.qs
diff --git a/src/Simulation/QsharpBase/Microsoft.Quantum.QSharp.Base.csproj b/src/Simulation/QsharpBase/Microsoft.Quantum.QSharp.Base.csproj
new file mode 100644
index 00000000000..6c83c7b7c3e
--- /dev/null
+++ b/src/Simulation/QsharpBase/Microsoft.Quantum.QSharp.Base.csproj
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ netstandard2.1
+ true
+ false
+ false
+
+
+
+ Microsoft
+ Base support for the Q# programming language.
+ See: https://docs.microsoft.com/en-us/quantum/relnotes/
+ MIT
+ https://github.com/microsoft/qsharp-runtime
+ https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png
+ Quantum Q# Qsharp
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Simulation/QsharpCore/Statements/Allocate.cs b/src/Simulation/QsharpBase/Statements/Allocate.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Statements/Allocate.cs
rename to src/Simulation/QsharpBase/Statements/Allocate.cs
diff --git a/src/Simulation/QsharpCore/Statements/Borrow.cs b/src/Simulation/QsharpBase/Statements/Borrow.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Statements/Borrow.cs
rename to src/Simulation/QsharpBase/Statements/Borrow.cs
diff --git a/src/Simulation/QsharpCore/Statements/Release.cs b/src/Simulation/QsharpBase/Statements/Release.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Statements/Release.cs
rename to src/Simulation/QsharpBase/Statements/Release.cs
diff --git a/src/Simulation/QsharpCore/Statements/Return.cs b/src/Simulation/QsharpBase/Statements/Return.cs
similarity index 100%
rename from src/Simulation/QsharpCore/Statements/Return.cs
rename to src/Simulation/QsharpBase/Statements/Return.cs
diff --git a/src/Simulation/QsharpBase/Utils.qs b/src/Simulation/QsharpBase/Utils.qs
new file mode 100644
index 00000000000..3c1a2c75612
--- /dev/null
+++ b/src/Simulation/QsharpBase/Utils.qs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+/// # Summary
+/// This namespace includes Q# intrinsic utilies.
+///
+/// # Remarks
+/// This namespace is opened automatically by the Q# compiler, so all
+/// elements of this namespace are always available.
+namespace Microsoft.Quantum.Intrinsic {
+ /// # Summary
+ /// The random operation takes an array of doubles as input, and returns
+ /// a randomly-selected index into the array as an `Int`.
+ /// The probability of selecting a specific index is proportional to the value
+ /// of the array element at that index.
+ /// Array elements that are equal to zero are ignored and their indices are never
+ /// returned. If any array element is less than zero,
+ /// or if no array element is greater than zero, then the operation fails.
+ ///
+ /// # Input
+ /// ## probs
+ /// An array of floating-point numbers proportional to the probability of
+ /// selecting each index.
+ ///
+ /// # Output
+ /// An integer $i$ with probability $\Pr(i) = p_i / \sum_i p_i$, where $p_i$
+ /// is the $i$th element of `probs`.
+ operation Random(probs : Double[]) : Int {
+ body intrinsic;
+ }
+
+ /// # Summary
+ /// Logs a message.
+ ///
+ /// # Input
+ /// ## msg
+ /// The message to be reported.
+ ///
+ /// # Remarks
+ /// The specific behavior of this function is simulator-dependent,
+ /// but in most cases the given message will be written to the console.
+ function Message(msg : String) : Unit {
+ body intrinsic;
+ }
+
+}
\ No newline at end of file
diff --git a/src/Simulation/QsharpCore/Intrinsic.qs b/src/Simulation/QsharpCore/Intrinsic.qs
index 28f0353dd86..00b626aff53 100644
--- a/src/Simulation/QsharpCore/Intrinsic.qs
+++ b/src/Simulation/QsharpCore/Intrinsic.qs
@@ -4,107 +4,6 @@
namespace Microsoft.Quantum.Intrinsic {
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Convert;
-
- /// # Summary
- /// The random operation takes an array of doubles as input, and returns
- /// a randomly-selected index into the array as an `Int`.
- /// The probability of selecting a specific index is proportional to the value
- /// of the array element at that index.
- /// Array elements that are equal to zero are ignored and their indices are never
- /// returned. If any array element is less than zero,
- /// or if no array element is greater than zero, then the operation fails.
- ///
- /// # Input
- /// ## probs
- /// An array of floating-point numbers proportional to the probability of
- /// selecting each index.
- ///
- /// # Output
- /// An integer $i$ with probability $\Pr(i) = p_i / \sum_i p_i$, where $p_i$
- /// is the $i$th element of `probs`.
- operation Random (probs : Double[]) : Int {
- body intrinsic;
- }
-
-
- /// # Summary
- /// Asserts that measuring the given qubits in the given Pauli basis will
- /// always have the given result.
- ///
- /// # Input
- /// ## bases
- /// A measurement effect to assert the probability of, expressed as a
- /// multi-qubit Pauli operator.
- /// ## qubits
- /// A register on which to make the assertion.
- /// ## result
- /// The expected result of `Measure(bases, qubits)`.
- /// ## msg
- /// A message to be reported if the assertion fails.
- ///
- /// # Remarks
- /// Note that the Adjoint and Controlled versions of this operation will not
- /// check the condition.
- ///
- /// # See Also
- /// - AssertProb
- operation Assert (bases : Pauli[], qubits : Qubit[], result : Result, msg : String) : Unit
- is Adj + Ctl {
- body intrinsic;
- }
-
-
- /// # Summary
- /// Asserts that measuring the given qubits in the given Pauli basis will have the given result
- /// with the given probability, within some tolerance.
- ///
- /// # Input
- /// ## bases
- /// A measurement effect to assert the probability of, expressed as a
- /// multi-qubit Pauli operator.
- /// ## qubits
- /// A register on which to make the assertion.
- /// ## result
- /// An expected result of `Measure(bases, qubits)`.
- /// ## prob
- /// The probability with which the given result is expected.
- /// ## msg
- /// A message to be reported if the assertion fails.
- ///
- /// # Example
- /// ```qsharp
- /// using (register = Qubit()) {
- /// H(register);
- /// AssertProb([PauliZ], [register], One, 0.5,
- /// "Measuring in conjugate basis did not give 50/50 results.", 1e-5);
- /// }
- /// ```
- ///
- /// # Remarks
- /// Note that the Adjoint and Controlled versions of this operation will not
- /// check the condition.
- ///
- /// # See Also
- /// - Assert
- operation AssertProb (bases : Pauli[], qubits : Qubit[], result : Result, prob : Double, msg : String, tol : Double) : Unit
- is Adj + Ctl {
- body intrinsic;
- }
-
-
- /// # Summary
- /// Logs a message.
- ///
- /// # Input
- /// ## msg
- /// The message to be reported.
- ///
- /// # Remarks
- /// The specific behavior of this function is simulator-dependent,
- /// but in most cases the given message will be written to the console.
- function Message (msg : String) : Unit {
- body intrinsic;
- }
//-------------------------------------------------
@@ -126,7 +25,8 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the Pauli $X$ gate.
- ///
+ ///
+ /// # Description
/// \begin{align}
/// \sigma_x \mathrel{:=}
/// \begin{bmatrix}
@@ -147,6 +47,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the Pauli $Y$ gate.
///
+ /// # Description
/// \begin{align}
/// \sigma_y \mathrel{:=}
/// \begin{bmatrix}
@@ -168,6 +69,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the Pauli $Z$ gate.
///
+ /// # Description
/// \begin{align}
/// \sigma_z \mathrel{:=}
/// \begin{bmatrix}
@@ -189,6 +91,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the Hadamard transformation to a single qubit.
///
+ /// # Description
/// \begin{align}
/// H \mathrel{:=}
/// \frac{1}{\sqrt{2}}
@@ -211,6 +114,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the π/4 phase gate to a single qubit.
///
+ /// # Description
/// \begin{align}
/// S \mathrel{:=}
/// \begin{bmatrix}
@@ -231,6 +135,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the π/8 gate to a single qubit.
///
+ /// # Description
/// \begin{align}
/// T \mathrel{:=}
/// \begin{bmatrix}
@@ -251,6 +156,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the controlled-NOT (CNOT) gate to a pair of qubits.
///
+ /// # Description
/// \begin{align}
/// \operatorname{CNOT} \mathrel{:=}
/// \begin{bmatrix}
@@ -316,6 +222,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the SWAP gate to a pair of qubits.
///
+ /// # Description
/// \begin{align}
/// \operatorname{SWAP} \mathrel{:=}
/// \begin{bmatrix}
@@ -360,6 +267,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies a rotation about the given Pauli axis.
///
+ /// # Description
/// \begin{align}
/// R_{\mu}(\theta) \mathrel{:=}
/// e^{-i \theta \sigma_{\mu} / 2},
@@ -388,6 +296,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// Applies a rotation about the given Pauli axis by an angle specified
/// as a dyadic fraction.
///
+ /// # Description
/// \begin{align}
/// R_{\mu}(n, k) \mathrel{:=}
/// e^{i \pi n \sigma_{\mu} / 2^k},
@@ -427,6 +336,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies a rotation about the $x$-axis by a given angle.
///
+ /// # Description
/// \begin{align}
/// R_x(\theta) \mathrel{:=}
/// e^{-i \theta \sigma_x / 2} =
@@ -464,6 +374,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies a rotation about the $y$-axis by a given angle.
///
+ /// # Description
/// \begin{align}
/// R_y(\theta) \mathrel{:=}
/// e^{-i \theta \sigma_y / 2} =
@@ -501,6 +412,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies a rotation about the $z$-axis by a given angle.
///
+ /// # Description
/// \begin{align}
/// R_z(\theta) \mathrel{:=}
/// e^{-i \theta \sigma_z / 2} =
@@ -538,6 +450,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies a rotation about the $\ket{1}$ state by a given angle.
///
+ /// # Description
/// \begin{align}
/// R_1(\theta) \mathrel{:=}
/// \operatorname{diag}(1, e^{i\theta}).
@@ -567,6 +480,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// Applies a rotation about the $\ket{1}$ state by an angle specified
/// as a dyadic fraction.
///
+ /// # Description
/// \begin{align}
/// R_1(n, k) \mathrel{:=}
/// \operatorname{diag}(1, e^{i \pi k / 2^n}).
@@ -604,6 +518,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// # Summary
/// Applies the exponential of a multi-qubit Pauli operator.
///
+ /// # Description
/// \begin{align}
/// e^{i \theta [P_0 \otimes P_1 \cdots P_{N-1}]},
/// \end{align}
@@ -629,6 +544,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// Applies the exponential of a multi-qubit Pauli operator
/// with an argument given by a dyadic fraction.
///
+ /// # Description
/// \begin{align}
/// e^{i \pi k [P_0 \otimes P_1 \cdots P_{N-1}] / 2^n},
/// \end{align}
@@ -662,6 +578,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// Performs a joint measurement of one or more qubits in the
/// specified Pauli bases.
///
+ /// # Description
/// The output result is given by the distribution:
/// \begin{align}
/// \Pr(\texttt{Zero} | \ket{\psi}) =
@@ -701,6 +618,7 @@ namespace Microsoft.Quantum.Intrinsic {
/// Performs a measurement of a single qubit in the
/// Pauli $Z$ basis.
///
+ /// # Description
/// The output result is given by
/// the distribution
/// \begin{align}
diff --git a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj
index 6fa6d8bc6a1..a07fa279f6b 100644
--- a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj
+++ b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj
@@ -27,6 +27,7 @@
+
diff --git a/src/Simulation/Simulators.Tests/StackTraceTests.cs b/src/Simulation/Simulators.Tests/StackTraceTests.cs
index 48c142d7e2b..e561ccd55b3 100644
--- a/src/Simulation/Simulators.Tests/StackTraceTests.cs
+++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs
@@ -97,8 +97,13 @@ public void AlwaysFail4Test()
for (int i = 0; i < stackFrames.Length; ++i)
{
- Assert.StartsWith(@"https://github.com/", stackFrames[i].GetURLFromPDB());
- Assert.EndsWith($"#L{stackFrames[i].FailedLineNumber}", stackFrames[i].GetURLFromPDB());
+ Console.WriteLine(stackFrames[i].GetURLFromPDB());
+ Assert.StartsWith(@"https://", stackFrames[i].GetURLFromPDB());
+ // Only check for correct line numbers if they are included in the trace.
+ if (stackFrames[i].GetURLFromPDB().Contains("#L"))
+ {
+ Assert.EndsWith($"#L{stackFrames[i].FailedLineNumber}", stackFrames[i].GetURLFromPDB());
+ }
}
StringBuilder builder = new StringBuilder();