From e3d9b48a7c00dd9f1fc4eba498c8d68ff92214a6 Mon Sep 17 00:00:00 2001 From: Robin Kuzmin <9372582+kuzminrobin@users.noreply.github.com> Date: Mon, 18 Oct 2021 19:23:56 -0700 Subject: [PATCH 1/2] Broken up QuantumSimulator into CommonNativeSimulator and QuantumSimulator (#853) --- src/Simulation/Common/QubitManager.cs | 31 +-- .../ApplyControlledX.cs | 4 +- .../ApplyControlledZ.cs | 4 +- .../ApplyUncontrolledH.cs | 4 +- .../ApplyUncontrolledRx.cs | 4 +- .../ApplyUncontrolledRy.cs | 4 +- .../ApplyUncontrolledRz.cs | 4 +- .../ApplyUncontrolledS.cs | 4 +- .../ApplyUncontrolledSAdj.cs | 4 +- .../ApplyUncontrolledSWAP.cs | 8 +- .../ApplyUncontrolledT.cs | 4 +- .../ApplyUncontrolledTAdj.cs | 4 +- .../ApplyUncontrolledX.cs | 4 +- .../ApplyUncontrolledY.cs | 4 +- .../ApplyUncontrolledZ.cs | 4 +- .../Assert.cs | 12 +- .../AssertProb.cs | 12 +- .../CommonNativeSimulator.cs | 191 +++++++++++++++++ .../Simulators/CommonNativeSimulator/Dump.cs | 100 +++++++++ .../Exp.cs | 6 +- .../Extensions.cs | 0 .../H.cs | 6 +- .../IsingXX.cs | 6 +- .../IsingYY.cs | 6 +- .../IsingZZ.cs | 6 +- .../M.cs | 4 +- .../MZ.cs | 4 +- .../Measure.cs | 4 +- .../CommonNativeSimulator/NativeWrappers.cs | 33 +++ .../Qubit.cs | 13 +- .../QubitManager.cs | 24 +-- .../R.cs | 6 +- .../Reset.cs | 6 +- .../Rx.cs | 6 +- .../Ry.cs | 6 +- .../Rz.cs | 6 +- .../S.cs | 10 +- .../SWAP.cs | 14 +- .../SimulatorBase.cs | 0 .../StackTrace.cs | 0 .../T.cs | 10 +- .../X.cs | 6 +- .../Y.cs | 6 +- .../Z.cs | 6 +- .../Simulators/QuantumSimulator/Dump.cs | 95 ++------- .../QuantumSimulator/NativeImports.cs | 76 ++++--- .../QuantumSimulator/NativeWrappers.cs | 145 +++++++++++++ .../QuantumSimulator/QuantumSimulator.cs | 195 +----------------- .../QuantumSimulator/StateDumper.cs | 11 +- 49 files changed, 682 insertions(+), 440 deletions(-) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyControlledX.cs (78%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyControlledZ.cs (78%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledH.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledRx.cs (80%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledRy.cs (80%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledRz.cs (80%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledS.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledSAdj.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledSWAP.cs (71%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledT.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledTAdj.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledX.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledY.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/ApplyUncontrolledZ.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Assert.cs (74%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/AssertProb.cs (80%) create mode 100644 src/Simulation/Simulators/CommonNativeSimulator/CommonNativeSimulator.cs create mode 100644 src/Simulation/Simulators/CommonNativeSimulator/Dump.cs rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Exp.cs (86%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Extensions.cs (100%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/H.cs (78%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/IsingXX.cs (85%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/IsingYY.cs (85%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/IsingZZ.cs (85%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/M.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/MZ.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Measure.cs (85%) create mode 100644 src/Simulation/Simulators/CommonNativeSimulator/NativeWrappers.cs rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Qubit.cs (55%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/QubitManager.cs (69%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/R.cs (85%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Reset.cs (79%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Rx.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Ry.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Rz.cs (81%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/S.cs (77%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/SWAP.cs (65%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/SimulatorBase.cs (100%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/StackTrace.cs (100%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/T.cs (77%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/X.cs (78%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Y.cs (78%) rename src/Simulation/Simulators/{QuantumSimulator => CommonNativeSimulator}/Z.cs (78%) create mode 100644 src/Simulation/Simulators/QuantumSimulator/NativeWrappers.cs diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 9b5faffe20f..0313b9fd732 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -321,13 +321,13 @@ public void Disable(IQArray qubitsToDisable) /// Allocates a qubit. /// Returns null if the qubit cannot be allocated. /// - protected virtual Qubit? Allocate(bool usedOnlyForBorrowing) + protected virtual Qubit Allocate(bool usedOnlyForBorrowing) { if (free == None) { if (!MayExtendCapacity) { - return null; + throw new NotEnoughQubits(1, this.FreeQubitsCount); } long oldNumQubits = NumQubits; @@ -398,12 +398,7 @@ public void Disable(IQArray qubitsToDisable) /// public Qubit Allocate() { - Qubit? qb = Allocate(usedOnlyForBorrowing: false); - if (qb == null) - { - throw new NotEnoughQubits(1, this.FreeQubitsCount); - } - return qb; + return Allocate(usedOnlyForBorrowing: false); } /// @@ -429,15 +424,7 @@ public IQArray Allocate(long numToAllocate) } for (int i = 0; i < numToAllocate; i++) { - Qubit? allocated = Allocate(usedOnlyForBorrowing: false); - if (allocated == null) - { - for (int k = 0; k < i; k++) - { - Release(result[k], wasUsedOnlyForBorrowing: false); - } - throw new NotEnoughQubits(numToAllocate, this.FreeQubitsCount); - } + Qubit allocated = Allocate(usedOnlyForBorrowing: false); result.Modify(i, allocated); } @@ -594,15 +581,7 @@ internal IQArray Borrow(long numToBorrow, HashSet qubitsInUse) { // Not enough qubits to borrow. Allocate what was not borrowed. for (long i = numBorrowed; i < numToBorrow; i++) { - Qubit? allocated = Allocate(usedOnlyForBorrowing: true); - if (allocated == null) - { - for (long k = numBorrowed; k < i; k++) - { - Release(borrowed[(int)k], wasUsedOnlyForBorrowing: true); - } - throw new NotEnoughQubits(numToBorrow, numBorrowed + this.FreeQubitsCount); - } + Qubit allocated = Allocate(usedOnlyForBorrowing: true); borrowed.Modify(i, allocated); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyControlledX.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledX.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/ApplyControlledX.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledX.cs index f8c3a68e3ef..2e7a5944f3c 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyControlledX.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledX.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyControlledX.Body(Qubit control, Qubit target) { this.CheckQubits(new QArray(new Qubit[]{ control, target })); - MCX(this.Id, 1, new uint[]{(uint)control.Id}, (uint)target.Id); + MCX(1, new uint[]{(uint)control.Id}, (uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyControlledZ.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledZ.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/ApplyControlledZ.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledZ.cs index 1f0ae75acdc..760f0d8fe5e 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyControlledZ.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyControlledZ.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyControlledZ.Body(Qubit control, Qubit target) { this.CheckQubits(new QArray(new Qubit[]{ control, target })); - MCZ(this.Id, 1, new uint[]{(uint)control.Id}, (uint)target.Id); + MCZ(1, new uint[]{(uint)control.Id}, (uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledH.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledH.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledH.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledH.cs index 242d2bfa069..6dbafb55d77 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledH.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledH.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledH.Body(Qubit target) { this.CheckQubit(target); - H(this.Id, (uint)target.Id); + H((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRx.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRx.cs similarity index 80% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRx.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRx.cs index 1881c6fb24b..ecbf61e66eb 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRx.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRx.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledRx.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliX, angle, (uint)target.Id); + R(Pauli.PauliX, angle, (uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRy.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRy.cs similarity index 80% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRy.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRy.cs index d06574ea663..77400a58075 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRy.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRy.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledRy.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliY, angle, (uint)target.Id); + R(Pauli.PauliY, angle, (uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRz.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRz.cs similarity index 80% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRz.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRz.cs index a0349868b44..31de582fd84 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledRz.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledRz.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledRz.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliZ, angle, (uint)target.Id); + R(Pauli.PauliZ, angle, (uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledS.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledS.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledS.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledS.cs index 3f106e2d5ae..9abcb19f4c4 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledS.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledS.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledS.Body(Qubit target) { this.CheckQubit(target); - S(this.Id, (uint)target.Id); + S((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSAdj.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSAdj.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSAdj.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSAdj.cs index 31da980a3b1..f50b097225c 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSAdj.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSAdj.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledSAdj.Body(Qubit target) { this.CheckQubit(target); - AdjS(this.Id, (uint)target.Id); + AdjS((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSWAP.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSWAP.cs similarity index 71% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSWAP.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSWAP.cs index 733db0889a2..f6042967b00 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledSWAP.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledSWAP.cs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledSWAP.Body(Qubit qubit1, Qubit qubit2) { @@ -16,9 +16,9 @@ void IIntrinsicApplyUncontrolledSWAP.Body(Qubit qubit1, Qubit qubit2) this.CheckQubits(new QArray(new Qubit[]{ qubit1, qubit2 })); - MCX(this.Id, 1, new uint[]{(uint)qubit1.Id}, (uint)qubit2.Id); - MCX(this.Id, 1, new uint[]{(uint)qubit2.Id}, (uint)qubit1.Id); - MCX(this.Id, 1, new uint[]{(uint)qubit1.Id}, (uint)qubit2.Id); + MCX(1, new uint[]{(uint)qubit1.Id}, (uint)qubit2.Id); + MCX(1, new uint[]{(uint)qubit2.Id}, (uint)qubit1.Id); + MCX(1, new uint[]{(uint)qubit1.Id}, (uint)qubit2.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledT.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledT.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledT.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledT.cs index dbbe5b337f5..dce12faedef 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledT.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledT.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledT.Body(Qubit target) { this.CheckQubit(target); - T(this.Id, (uint)target.Id); + T((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledTAdj.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledTAdj.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledTAdj.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledTAdj.cs index fda29c8cd5f..818447f16bd 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledTAdj.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledTAdj.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledTAdj.Body(Qubit target) { this.CheckQubit(target); - AdjT(this.Id, (uint)target.Id); + AdjT((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledX.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledX.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledX.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledX.cs index 673ca0742da..f40fd124921 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledX.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledX.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledX.Body(Qubit target) { this.CheckQubit(target); - X(this.Id, (uint)target.Id); + X((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledY.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledY.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledY.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledY.cs index 3f1d13c6a53..aa52dff46b8 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledY.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledY.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledY.Body(Qubit target) { this.CheckQubit(target); - Y(this.Id, (uint)target.Id); + Y((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledZ.cs b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledZ.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledZ.cs rename to src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledZ.cs index 10d6d31aca8..f47bec9f114 100644 --- a/src/Simulation/Simulators/QuantumSimulator/ApplyUncontrolledZ.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/ApplyUncontrolledZ.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicApplyUncontrolledZ.Body(Qubit target) { this.CheckQubit(target); - Z(this.Id, (uint)target.Id); + Z((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Assert.cs b/src/Simulation/Simulators/CommonNativeSimulator/Assert.cs similarity index 74% rename from src/Simulation/Simulators/QuantumSimulator/Assert.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Assert.cs index fc54ba1fcc1..9d7d1681aa8 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Assert.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Assert.cs @@ -7,13 +7,17 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { + // `QSimAssert` makes an impression that it is never used, + // but since it inherits from Quantum.Diagnostics.AssertMeasurement + // (which is a C# class that corresponds to a Q# operation in our core libraries), it will be automatically used. + // It is instantiated via reflection, hence we don't see it easily in the code. public class QSimAssert : Microsoft.Quantum.Diagnostics.AssertMeasurement { - private QuantumSimulator Simulator { get; } + private CommonNativeSimulator Simulator { get; } - public QSimAssert(QuantumSimulator m) : base(m) + public QSimAssert(CommonNativeSimulator m) : base(m) { this.Simulator = m; } @@ -32,7 +36,7 @@ public QSimAssert(QuantumSimulator m) : base(m) var tolerance = 1.0e-10; var expectedPr = result == Result.Zero ? 0.0 : 1.0; - var ensemblePr = JointEnsembleProbability(this.Simulator.Id, (uint)paulis.Length, paulis.ToArray(), qubits.GetIds()); + var ensemblePr = this.Simulator.JointEnsembleProbability((uint)paulis.Length, paulis.ToArray(), qubits.GetIds()); if (Abs(ensemblePr - expectedPr) > tolerance) { diff --git a/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs b/src/Simulation/Simulators/CommonNativeSimulator/AssertProb.cs similarity index 80% rename from src/Simulation/Simulators/QuantumSimulator/AssertProb.cs rename to src/Simulation/Simulators/CommonNativeSimulator/AssertProb.cs index 955ba22929b..fb038b23b4b 100644 --- a/src/Simulation/Simulators/QuantumSimulator/AssertProb.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/AssertProb.cs @@ -7,13 +7,17 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { + // `QSimAssertProb` makes an impression that it is never used, + // but since it inherits from Quantum.Diagnostics.AssertMeasurementProbability + // (which is a C# class that corresponds to a Q# operation in our core libraries), it will be automatically used. + // It is instantiated via reflection, hence we don't see it easily in the code. public class QSimAssertProb : Microsoft.Quantum.Diagnostics.AssertMeasurementProbability { - private QuantumSimulator Simulator { get; } + private CommonNativeSimulator Simulator { get; } - public QSimAssertProb(QuantumSimulator m) : base(m) + public QSimAssertProb(CommonNativeSimulator m) : base(m) { this.Simulator = m; } @@ -38,7 +42,7 @@ public QSimAssertProb(QuantumSimulator m) : base(m) expectedPr = 1 - expectedPr; } - var ensemblePr = JointEnsembleProbability(Simulator.Id, (uint)paulis.Length, paulis.ToArray(), qubits.GetIds()); + var ensemblePr = this.Simulator.JointEnsembleProbability((uint)paulis.Length, paulis.ToArray(), qubits.GetIds()); if (Abs(ensemblePr - expectedPr) > tol) { diff --git a/src/Simulation/Simulators/CommonNativeSimulator/CommonNativeSimulator.cs b/src/Simulation/Simulators/CommonNativeSimulator/CommonNativeSimulator.cs new file mode 100644 index 00000000000..dda46fc992a --- /dev/null +++ b/src/Simulation/Simulators/CommonNativeSimulator/CommonNativeSimulator.cs @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.Common; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Simulators.Exceptions; +using Microsoft.Quantum.Intrinsic.Interfaces; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Quantum.Simulation.Simulators +{ + public abstract partial class CommonNativeSimulator : SimulatorBase, IQSharpCore, IType1Core, IType2Core, IType3Core, IDisposable + { + /// + /// Creates a an instance of a quantum simulator. + /// + /// If set to true, the exception is thrown when trying to release qubits not in zero state. + /// Seed for the random number generator used by a simulator for measurement outcomes and the Random operation. + /// If true, Borrowing qubits will be disabled, and a new qubit will be allocated instead every time borrowing is requested. Performance may improve. + private protected CommonNativeSimulator( + bool throwOnReleasingQubitsNotInZeroState = true, + UInt32? randomNumberGeneratorSeed = null, + bool disableBorrowing = false) + : base( + new QSimQubitManager(throwOnReleasingQubitsNotInZeroState, disableBorrowing : disableBorrowing), + (int?)randomNumberGeneratorSeed + ) + { + Debug.Assert(this.QubitManager != null); + ((QSimQubitManager)this.QubitManager).Simulator = this; + } + + public uint Id { get; protected set; } + + public override string Name + { + get + { + return "CommonNativeSimulator"; + } + } + + static void CheckQubitInUse(Qubit q, bool[] used) + { + if (q == null) throw new ArgumentNullException(nameof(q), "Trying to perform a primitive operation on a null Qubit"); + + if (used[q.Id]) + { + throw new NotDistinctQubits(q); + } + + used[q.Id] = true; + } + + /// + /// Makes sure the angle for a rotation or exp operation is not NaN or Infinity. + /// + static void CheckAngle(double angle) + { + IgnorableAssert.Assert(!(double.IsNaN(angle) || double.IsInfinity(angle)), "Invalid angle for rotation/exponentiation."); + + if (double.IsNaN(angle)) throw new ArgumentOutOfRangeException("angle", "Angle can't be NaN."); + if (double.IsInfinity(angle)) throw new ArgumentOutOfRangeException("angle", "Angle can't be Infity."); + } + + /// + /// Makes sure the target qubit of an operation is valid. In particular it checks that the qubit instance is not null. + /// Also sets the isMeasured flag to false for each qubit + /// + void CheckQubit(Qubit q1) + { + if (q1 == null) throw new ArgumentNullException(nameof(q1), "Trying to perform a primitive operation on a null Qubit"); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q1.IsMeasured = false; + } + + /// + /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that + /// - none of the qubits are null + /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit + /// + bool[] CheckQubits(IQArray ctrls, Qubit q1) + { + bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; + + CheckQubitInUse(q1, used); + q1.IsMeasured = false; + + if (ctrls != null && ctrls.Length > 0) + { + foreach (var q in ctrls) + { + CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; + } + } + + return used; + } + + + /// + /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that + /// - none of the qubits are null + /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit + /// + bool[] CheckQubits(IQArray targets) + { + if (targets == null) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on a null Qubit array."); + if (targets.Length == 0) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on an empty Qubit array."); + + bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; + + foreach (var q in targets) + { + CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; + } + + return used; + } + + /// + /// Intended to be used with simulator functions like Dump, Assert, AssertProb + /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that + /// - none of the qubits are null + /// - there are no duplicated qubits + /// + bool[] CheckAndPreserveQubits(IQArray targets) + { + if (targets == null) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on a null Qubit array."); + if (targets.Length == 0) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on an empty Qubit array."); + + bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; + + foreach (var q in targets) + { + CheckQubitInUse(q, used); + } + + return used; + } + + /// + /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that + /// - none of the qubits are null + /// - there are no duplicated qubits + /// Also sets the isMeasured flag to false for each qubit + /// + bool[] CheckQubits(IQArray ctrls, IQArray targets) + { + bool[] used = CheckQubits(targets); + + if (ctrls != null) + { + foreach (var q in ctrls) + { + CheckQubitInUse(q, used); + //setting qubit as not measured to not allow release in case of gate operation on qubit + q.IsMeasured = false; + } + } + + return used; + } + + static void SafeControlled(IQArray ctrls, Action noControlsAction, Action controlledAction) + { + if (ctrls == null || ctrls.Length == 0) + { + noControlsAction(); + } + else + { + uint count = (uint)ctrls.Length; + controlledAction(count, ctrls.GetIds()); + } + } + + public virtual void Dispose() + { + } + } +} diff --git a/src/Simulation/Simulators/CommonNativeSimulator/Dump.cs b/src/Simulation/Simulators/CommonNativeSimulator/Dump.cs new file mode 100644 index 00000000000..51fa1c153fa --- /dev/null +++ b/src/Simulation/Simulators/CommonNativeSimulator/Dump.cs @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Linq; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.Simulators +{ + public partial class CommonNativeSimulator + { + protected virtual QVoid process(Action channel, IQArray? qubits) + { + return QVoid.Instance; + } + + /// + /// Dumps the wave function for the given qubits into the given target. + /// If the target is QVoid or an empty string, it dumps it to the console + /// using the `Message` function, otherwise it dumps the content into a file + /// with the given name. + /// If the given qubits is null, it dumps the entire wave function, otherwise + /// it attempts to create the wave function or the resulting subsystem; if it fails + /// because the qubits are entangled with some external qubit, it just generates a message. + /// + protected virtual QVoid Dump(T target, IQArray? qubits = null) + { + var filename = (target is QVoid) ? "" : target.ToString(); + var logMessage = this.Get, Microsoft.Quantum.Intrinsic.Message>(); + + // If no file provided, use `Message` to generate the message into the console; + if (string.IsNullOrWhiteSpace(filename)) + { + var op = this.Get, Microsoft.Quantum.Intrinsic.Message>(); + return process((msg) => op.Apply(msg), qubits); + } + else + { + try + { + using (var file = new StreamWriter(filename)) + { + return process(file.WriteLine, qubits); + } + } + catch (Exception e) + { + logMessage.Apply($"[warning] Unable to write state to '{filename}' ({e.Message})"); + return QVoid.Instance; + } + } + } + + // `QsimDumpMachine` makes an impression that it is never used, + // but since it inherits from Quantum.Diagnostics.DumpMachine (which is a C# class that corresponds to a + // Q# operation in our core libraries), it will be automatically used. + // It is instantiated via reflection, hence we don't see it easily in the code. + public class QsimDumpMachine : Quantum.Diagnostics.DumpMachine + { + private CommonNativeSimulator Simulator { get; } + + public QsimDumpMachine(CommonNativeSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func __Body__ => (location) => + { + if (location == null) { throw new ArgumentNullException(nameof(location)); } + + return Simulator.Dump(location); + }; + } + + // `QSimDumpRegister` makes an impression that it is never used, + // but since it inherits from Quantum.Diagnostics.QSimDumpRegister (which is a C# class that corresponds to a + // Q# operation in our core libraries), it will be automatically used. + // It is instantiated via reflection, hence we don't see it easily in the code. + public class QSimDumpRegister : Quantum.Diagnostics.DumpRegister + { + private CommonNativeSimulator Simulator { get; } + + public QSimDumpRegister(CommonNativeSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(T, IQArray), QVoid> __Body__ => (__in) => + { + var (location, qubits) = __in; + + if (location == null) { throw new ArgumentNullException(nameof(location)); } + Simulator.CheckAndPreserveQubits(qubits); + + return Simulator.Dump(location, qubits); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumSimulator/Exp.cs b/src/Simulation/Simulators/CommonNativeSimulator/Exp.cs similarity index 86% rename from src/Simulation/Simulators/QuantumSimulator/Exp.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Exp.cs index 9d1b11511f4..61233f2d17b 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Exp.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Exp.cs @@ -7,7 +7,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicExp.Body(IQArray paulis, double angle, IQArray targets) { @@ -19,7 +19,7 @@ void IIntrinsicExp.Body(IQArray paulis, double angle, IQArray targ throw new InvalidOperationException($"Both input arrays for Exp (paulis, targets), must be of same size."); } - Exp(this.Id, (uint)paulis.Length, paulis.ToArray(), angle, targets.GetIds()); + Exp((uint)paulis.Length, paulis.ToArray(), angle, targets.GetIds()); } void IIntrinsicExp.AdjointBody(IQArray paulis, double angle, IQArray targets) @@ -39,7 +39,7 @@ void IIntrinsicExp.ControlledBody(IQArray controls, IQArray paulis SafeControlled(controls, () => ((IIntrinsicExp)this).Body(paulis, angle, targets), - (count, ids) => MCExp(this.Id, (uint)paulis.Length, paulis.ToArray(), angle, count, ids, targets.GetIds())); + (count, ids) => MCExp((uint)paulis.Length, paulis.ToArray(), angle, count, ids, targets.GetIds())); } void IIntrinsicExp.ControlledAdjointBody(IQArray controls, IQArray paulis, double angle, IQArray targets) diff --git a/src/Simulation/Simulators/QuantumSimulator/Extensions.cs b/src/Simulation/Simulators/CommonNativeSimulator/Extensions.cs similarity index 100% rename from src/Simulation/Simulators/QuantumSimulator/Extensions.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Extensions.cs diff --git a/src/Simulation/Simulators/QuantumSimulator/H.cs b/src/Simulation/Simulators/CommonNativeSimulator/H.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/H.cs rename to src/Simulation/Simulators/CommonNativeSimulator/H.cs index 3df34308f06..179c363b987 100644 --- a/src/Simulation/Simulators/QuantumSimulator/H.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/H.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicH.Body(Qubit target) { this.CheckQubit(target); - H(this.Id, (uint)target.Id); + H((uint)target.Id); } void IIntrinsicH.ControlledBody(IQArray controls, Qubit target) @@ -21,7 +21,7 @@ void IIntrinsicH.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicH)this).Body(target), - (count, ids) => MCH(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCH(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/IsingXX.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs similarity index 85% rename from src/Simulation/Simulators/QuantumSimulator/IsingXX.cs rename to src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs index f372f9a02de..5f114db803a 100644 --- a/src/Simulation/Simulators/QuantumSimulator/IsingXX.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicIsingXX.Body(double angle, Qubit target1, Qubit target2) { @@ -15,7 +15,7 @@ void IIntrinsicIsingXX.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp(this.Id, (uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); } void IIntrinsicIsingXX.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingXX.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp(this.Id, (uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/IsingYY.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs similarity index 85% rename from src/Simulation/Simulators/QuantumSimulator/IsingYY.cs rename to src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs index c733988a2cd..1aa000ec554 100644 --- a/src/Simulation/Simulators/QuantumSimulator/IsingYY.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicIsingYY.Body(double angle, Qubit target1, Qubit target2) { @@ -15,7 +15,7 @@ void IIntrinsicIsingYY.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp(this.Id, (uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); } void IIntrinsicIsingYY.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingYY.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp(this.Id, (uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/IsingZZ.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs similarity index 85% rename from src/Simulation/Simulators/QuantumSimulator/IsingZZ.cs rename to src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs index e19c69347d3..ffdef477228 100644 --- a/src/Simulation/Simulators/QuantumSimulator/IsingZZ.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicIsingZZ.Body(double angle, Qubit target1, Qubit target2) { @@ -15,7 +15,7 @@ void IIntrinsicIsingZZ.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp(this.Id, (uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); } void IIntrinsicIsingZZ.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingZZ.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp(this.Id, (uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/M.cs b/src/Simulation/Simulators/CommonNativeSimulator/M.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/M.cs rename to src/Simulation/Simulators/CommonNativeSimulator/M.cs index 0777dd05c54..a258a29ec91 100644 --- a/src/Simulation/Simulators/QuantumSimulator/M.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/M.cs @@ -6,14 +6,14 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { Result IIntrinsicM.Body(Qubit target) { this.CheckQubit(target); //setting qubit as measured to allow for release target.IsMeasured = true; - return M(this.Id, (uint)target.Id).ToResult(); + return M((uint)target.Id).ToResult(); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/MZ.cs b/src/Simulation/Simulators/CommonNativeSimulator/MZ.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/MZ.cs rename to src/Simulation/Simulators/CommonNativeSimulator/MZ.cs index 2d4cdbc4d94..2110bf96ff8 100644 --- a/src/Simulation/Simulators/QuantumSimulator/MZ.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/MZ.cs @@ -6,14 +6,14 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { Result IIntrinsicMZ.Body(Qubit target) { this.CheckQubit(target); //setting qubit as measured to allow for release target.IsMeasured = true; - return M(this.Id, (uint)target.Id).ToResult(); + return M((uint)target.Id).ToResult(); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Measure.cs b/src/Simulation/Simulators/CommonNativeSimulator/Measure.cs similarity index 85% rename from src/Simulation/Simulators/QuantumSimulator/Measure.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Measure.cs index 4ed4696dad0..e787d9aa707 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Measure.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Measure.cs @@ -7,7 +7,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { Result IIntrinsicMeasure.Body(IQArray paulis, IQArray targets) { @@ -22,7 +22,7 @@ Result IIntrinsicMeasure.Body(IQArray paulis, IQArray targets) // that qubit as measured. targets[0].IsMeasured = true; } - return Measure(this.Id, (uint)paulis.Length, paulis.ToArray(), targets.GetIds()).ToResult(); + return Measure((uint)paulis.Length, paulis.ToArray(), targets.GetIds()).ToResult(); } } } diff --git a/src/Simulation/Simulators/CommonNativeSimulator/NativeWrappers.cs b/src/Simulation/Simulators/CommonNativeSimulator/NativeWrappers.cs new file mode 100644 index 00000000000..7e33cea1441 --- /dev/null +++ b/src/Simulation/Simulators/CommonNativeSimulator/NativeWrappers.cs @@ -0,0 +1,33 @@ +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.Simulators +{ + public partial class CommonNativeSimulator + { + protected abstract double JointEnsembleProbability(uint n, Pauli[] b, uint[] q); + protected abstract void Exp(uint n, Pauli[] paulis, double angle, uint[] ids); + protected abstract void MCExp(uint n, Pauli[] paulis, double angle, uint nc, uint[] ctrls, uint[] ids); + protected abstract void H(uint qubit); + protected abstract void MCH(uint count, uint[] ctrls, uint qubit); + protected abstract uint M(uint q); + protected abstract uint Measure(uint n, Pauli[] b, uint[] ids); + protected abstract void AllocateOne(uint qubit_id); + protected abstract bool ReleaseOne(uint qubit_id); + protected abstract void R(Pauli basis, double angle, uint qubit); + protected abstract void MCR(Pauli basis, double angle, uint count, uint[] ctrls, uint qubit); + protected abstract void S(uint qubit); + protected abstract void AdjS(uint qubit); + protected abstract void MCS(uint count, uint[] ctrls, uint qubit); + protected abstract void MCAdjS(uint count, uint[] ctrls, uint qubit); + protected abstract void T(uint qubit); + protected abstract void AdjT(uint qubit); + protected abstract void MCT(uint count, uint[] ctrls, uint qubit); + protected abstract void MCAdjT(uint count, uint[] ctrls, uint qubit); + protected abstract void X(uint qubit); + protected abstract void MCX(uint count, uint[] ctrls, uint qubit); + protected abstract void Y(uint qubit); + protected abstract void MCY(uint count, uint[] ctrls, uint qubit); + protected abstract void Z(uint qubit); + protected abstract void MCZ(uint count, uint[] ctrls, uint qubit); + } +} diff --git a/src/Simulation/Simulators/QuantumSimulator/Qubit.cs b/src/Simulation/Simulators/CommonNativeSimulator/Qubit.cs similarity index 55% rename from src/Simulation/Simulators/QuantumSimulator/Qubit.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Qubit.cs index 02424dfbc3e..76ab9222808 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Qubit.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Qubit.cs @@ -8,22 +8,21 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator : SimulatorBase, IDisposable + public partial class CommonNativeSimulator : SimulatorBase, IDisposable { class QSimQubit : Qubit { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private static Pauli[] PAULI_Z = new Pauli[] { Pauli.PauliZ }; + + private CommonNativeSimulator Simulator { get; } - public QSimQubit(int id, uint simulatorId) : base(id) + public QSimQubit(int id, CommonNativeSimulator sim) : base(id) { - this.SimulatorId = simulatorId; + this.Simulator = sim; } - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public uint SimulatorId { get; } - - public double Probability => JointEnsembleProbability(this.SimulatorId, 1, PAULI_Z, new uint[] { (uint)this.Id }); + public double Probability => this.Simulator.JointEnsembleProbability(1, PAULI_Z, new uint[] { (uint)this.Id }); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs similarity index 69% rename from src/Simulation/Simulators/QuantumSimulator/QubitManager.cs rename to src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs index b1bcc7b09fa..c32ff84800d 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs @@ -8,13 +8,15 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { - class QSimQubitManager : QubitManager + protected class QSimQubitManager : QubitManager { readonly bool throwOnReleasingQubitsNotInZeroState; - public uint SimulatorId { get; private set; } + public CommonNativeSimulator? Simulator { get; set; } // Must not be nullable (and public). But we cannot + // initialize it properly _during construction_. We initialize it _after construction_. + // That is why it is nullable and public. public QSimQubitManager(bool throwOnReleasingQubitsNotInZeroState = true, long qubitCapacity = 32, bool mayExtendCapacity = true, bool disableBorrowing = false) : base(qubitCapacity, mayExtendCapacity, disableBorrowing) @@ -22,11 +24,6 @@ public QSimQubitManager(bool throwOnReleasingQubitsNotInZeroState = true, long q this.throwOnReleasingQubitsNotInZeroState = throwOnReleasingQubitsNotInZeroState; } - public void Init(uint simulatorId) - { - this.SimulatorId = simulatorId; - } - /// /// The max number used as qubit id so far. /// @@ -34,20 +31,22 @@ public void Init(uint simulatorId) public override Qubit CreateQubitObject(long id) { - Debug.Assert(id < 50, "Using a qubit id > 50. This is a full-state simulator! Validating ids uniquenes might start becoming slow."); + Debug.Assert(id < 50, "Using a qubit id > 50. This is a full-state simulator! Validating ids uniqueness might start becoming slow."); if (id >= this.MaxId) { this.MaxId = id + 1; } - return new QSimQubit((int)id, SimulatorId); + Debug.Assert(Simulator != null); + return new QSimQubit((int)id, Simulator); } protected override Qubit Allocate(bool usedOnlyForBorrowing) { Qubit qubit = base.Allocate(usedOnlyForBorrowing); - if (qubit != null) { AllocateOne(this.SimulatorId, (uint)qubit.Id); } + Debug.Assert(Simulator != null); + Simulator.AllocateOne((uint)qubit.Id); return qubit; } @@ -56,7 +55,8 @@ protected override void Release(Qubit qubit, bool wasUsedOnlyForBorrowing) base.Release(qubit, wasUsedOnlyForBorrowing); if (qubit != null) { - bool isReleasedQubitZero = ReleaseOne(this.SimulatorId, (uint)qubit.Id); + Debug.Assert(Simulator != null); + bool isReleasedQubitZero = Simulator.ReleaseOne((uint)qubit.Id); if (!(isReleasedQubitZero || qubit.IsMeasured) && throwOnReleasingQubitsNotInZeroState) { throw new ReleasedQubitsAreNotInZeroState(); diff --git a/src/Simulation/Simulators/QuantumSimulator/R.cs b/src/Simulation/Simulators/CommonNativeSimulator/R.cs similarity index 85% rename from src/Simulation/Simulators/QuantumSimulator/R.cs rename to src/Simulation/Simulators/CommonNativeSimulator/R.cs index e0597eb2783..bfdb35c9e5d 100644 --- a/src/Simulation/Simulators/QuantumSimulator/R.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/R.cs @@ -6,14 +6,14 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicR.Body(Pauli pauli, double angle, Qubit target) { this.CheckQubit(target); CheckAngle(angle); - R(this.Id, pauli, angle, (uint)target.Id); + R(pauli, angle, (uint)target.Id); } void IIntrinsicR.AdjointBody(Pauli pauli, double angle, Qubit target) @@ -28,7 +28,7 @@ void IIntrinsicR.ControlledBody(IQArray controls, Pauli pauli, double ang SafeControlled(controls, () => ((IIntrinsicR)this).Body(pauli, angle, target), - (count, ids) => MCR(this.Id, pauli, angle, count, ids, (uint)target.Id)); + (count, ids) => MCR(pauli, angle, count, ids, (uint)target.Id)); } diff --git a/src/Simulation/Simulators/QuantumSimulator/Reset.cs b/src/Simulation/Simulators/CommonNativeSimulator/Reset.cs similarity index 79% rename from src/Simulation/Simulators/QuantumSimulator/Reset.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Reset.cs index a8bce353976..065ba0a615d 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Reset.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Reset.cs @@ -6,17 +6,17 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicReset.Body(Qubit target) { // The native simulator doesn't have a reset operation, so simulate // it via an M follow by a conditional X. this.CheckQubit(target); - var res = M(this.Id, (uint)target.Id); + var res = M((uint)target.Id); if (res == 1) { - X(this.Id, (uint)target.Id); + X((uint)target.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Rx.cs b/src/Simulation/Simulators/CommonNativeSimulator/Rx.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/Rx.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Rx.cs index 32f65bd2d82..4d6a6449e64 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Rx.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Rx.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicRx.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliX, angle, (uint)target.Id); + R(Pauli.PauliX, angle, (uint)target.Id); } void IIntrinsicRx.AdjointBody(double angle, Qubit target) @@ -24,7 +24,7 @@ void IIntrinsicRx.ControlledBody(IQArray controls, double angle, Qubit ta { this.CheckQubits(controls, target); CheckAngle(angle); - MCR(this.Id, Pauli.PauliX, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); + MCR(Pauli.PauliX, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); } void IIntrinsicRx.ControlledAdjointBody(IQArray controls, double angle, Qubit target) diff --git a/src/Simulation/Simulators/QuantumSimulator/Ry.cs b/src/Simulation/Simulators/CommonNativeSimulator/Ry.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/Ry.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Ry.cs index b76cca3ec86..710d805bcd8 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Ry.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Ry.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicRy.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliY, angle, (uint)target.Id); + R(Pauli.PauliY, angle, (uint)target.Id); } void IIntrinsicRy.AdjointBody(double angle, Qubit target) @@ -24,7 +24,7 @@ void IIntrinsicRy.ControlledBody(IQArray controls, double angle, Qubit ta { this.CheckQubits(controls, target); CheckAngle(angle); - MCR(this.Id, Pauli.PauliY, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); + MCR(Pauli.PauliY, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); } void IIntrinsicRy.ControlledAdjointBody(IQArray controls, double angle, Qubit target) diff --git a/src/Simulation/Simulators/QuantumSimulator/Rz.cs b/src/Simulation/Simulators/CommonNativeSimulator/Rz.cs similarity index 81% rename from src/Simulation/Simulators/QuantumSimulator/Rz.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Rz.cs index 8f0b259ca95..10ea0196fea 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Rz.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Rz.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicRz.Body(double angle, Qubit target) { this.CheckQubit(target, nameof(target)); CheckAngle(angle); - R(this.Id, Pauli.PauliZ, angle, (uint)target.Id); + R(Pauli.PauliZ, angle, (uint)target.Id); } void IIntrinsicRz.AdjointBody(double angle, Qubit target) @@ -24,7 +24,7 @@ void IIntrinsicRz.ControlledBody(IQArray controls, double angle, Qubit ta { this.CheckQubits(controls, target); CheckAngle(angle); - MCR(this.Id, Pauli.PauliZ, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); + MCR(Pauli.PauliZ, angle, (uint)controls.Length, controls.GetIds(), (uint)target.Id); } void IIntrinsicRz.ControlledAdjointBody(IQArray controls, double angle, Qubit target) diff --git a/src/Simulation/Simulators/QuantumSimulator/S.cs b/src/Simulation/Simulators/CommonNativeSimulator/S.cs similarity index 77% rename from src/Simulation/Simulators/QuantumSimulator/S.cs rename to src/Simulation/Simulators/CommonNativeSimulator/S.cs index f3a06adab56..2254039c66f 100644 --- a/src/Simulation/Simulators/QuantumSimulator/S.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/S.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicS.Body(Qubit target) { this.CheckQubit(target); - S(this.Id, (uint)target.Id); + S((uint)target.Id); } void IIntrinsicS.ControlledBody(IQArray controls, Qubit target) @@ -21,14 +21,14 @@ void IIntrinsicS.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicS)this).Body(target), - (count, ids) => MCS(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCS(count, ids, (uint)target.Id)); } void IIntrinsicS.AdjointBody(Qubit target) { this.CheckQubit(target); - AdjS(this.Id, (uint)target.Id); + AdjS((uint)target.Id); } void IIntrinsicS.ControlledAdjointBody(IQArray controls, Qubit target) @@ -37,7 +37,7 @@ void IIntrinsicS.ControlledAdjointBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicS)this).AdjointBody(target), - (count, ids) => MCAdjS(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCAdjS(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/SWAP.cs b/src/Simulation/Simulators/CommonNativeSimulator/SWAP.cs similarity index 65% rename from src/Simulation/Simulators/QuantumSimulator/SWAP.cs rename to src/Simulation/Simulators/CommonNativeSimulator/SWAP.cs index b0be124a3b7..b444dba0d03 100644 --- a/src/Simulation/Simulators/QuantumSimulator/SWAP.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/SWAP.cs @@ -7,7 +7,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicSWAP.Body(Qubit target1, Qubit target2) { @@ -15,9 +15,9 @@ void IIntrinsicSWAP.Body(Qubit target1, Qubit target2) var ctrls2 = new QArray(target2); this.CheckQubits(ctrls1, target2); - MCX(this.Id, (uint)ctrls1.Length, ctrls1.GetIds(), (uint)target2.Id); - MCX(this.Id, (uint)ctrls2.Length, ctrls2.GetIds(), (uint)target1.Id); - MCX(this.Id, (uint)ctrls1.Length, ctrls1.GetIds(), (uint)target2.Id); + MCX((uint)ctrls1.Length, ctrls1.GetIds(), (uint)target2.Id); + MCX((uint)ctrls2.Length, ctrls2.GetIds(), (uint)target1.Id); + MCX((uint)ctrls1.Length, ctrls1.GetIds(), (uint)target2.Id); } void IIntrinsicSWAP.ControlledBody(IQArray controls, Qubit target1, Qubit target2) @@ -32,9 +32,9 @@ void IIntrinsicSWAP.ControlledBody(IQArray controls, Qubit target1, Qubit var ctrls_2 = QArray.Add(controls, new QArray(target2)); this.CheckQubits(ctrls_1, target2); - MCX(this.Id, (uint)ctrls_1.Length, ctrls_1.GetIds(), (uint)target2.Id); - MCX(this.Id, (uint)ctrls_2.Length, ctrls_2.GetIds(), (uint)target1.Id); - MCX(this.Id, (uint)ctrls_1.Length, ctrls_1.GetIds(), (uint)target2.Id); + MCX((uint)ctrls_1.Length, ctrls_1.GetIds(), (uint)target2.Id); + MCX((uint)ctrls_2.Length, ctrls_2.GetIds(), (uint)target1.Id); + MCX((uint)ctrls_1.Length, ctrls_1.GetIds(), (uint)target2.Id); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs b/src/Simulation/Simulators/CommonNativeSimulator/SimulatorBase.cs similarity index 100% rename from src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs rename to src/Simulation/Simulators/CommonNativeSimulator/SimulatorBase.cs diff --git a/src/Simulation/Simulators/QuantumSimulator/StackTrace.cs b/src/Simulation/Simulators/CommonNativeSimulator/StackTrace.cs similarity index 100% rename from src/Simulation/Simulators/QuantumSimulator/StackTrace.cs rename to src/Simulation/Simulators/CommonNativeSimulator/StackTrace.cs diff --git a/src/Simulation/Simulators/QuantumSimulator/T.cs b/src/Simulation/Simulators/CommonNativeSimulator/T.cs similarity index 77% rename from src/Simulation/Simulators/QuantumSimulator/T.cs rename to src/Simulation/Simulators/CommonNativeSimulator/T.cs index 25ca2f61d48..5d52c89a953 100644 --- a/src/Simulation/Simulators/QuantumSimulator/T.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/T.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicT.Body(Qubit target) { this.CheckQubit(target); - T(this.Id, (uint)target.Id); + T((uint)target.Id); } void IIntrinsicT.ControlledBody(IQArray controls, Qubit target) @@ -21,14 +21,14 @@ void IIntrinsicT.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicT)this).Body(target), - (count, ids) => MCT(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCT(count, ids, (uint)target.Id)); } void IIntrinsicT.AdjointBody(Qubit target) { this.CheckQubit(target); - AdjT(this.Id, (uint)target.Id); + AdjT((uint)target.Id); } void IIntrinsicT.ControlledAdjointBody(IQArray controls, Qubit target) @@ -37,7 +37,7 @@ void IIntrinsicT.ControlledAdjointBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicT)this).AdjointBody(target), - (count, ids) => MCAdjT(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCAdjT(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/X.cs b/src/Simulation/Simulators/CommonNativeSimulator/X.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/X.cs rename to src/Simulation/Simulators/CommonNativeSimulator/X.cs index 7af68a2b261..9c54616a134 100644 --- a/src/Simulation/Simulators/QuantumSimulator/X.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/X.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicX.Body(Qubit target) { this.CheckQubit(target); - X(this.Id, (uint)target.Id); + X((uint)target.Id); } void IIntrinsicX.ControlledBody(IQArray controls, Qubit target) @@ -21,7 +21,7 @@ void IIntrinsicX.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicX)this).Body(target), - (count, ids) => MCX(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCX(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Y.cs b/src/Simulation/Simulators/CommonNativeSimulator/Y.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/Y.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Y.cs index 8858b2202dd..10613ceed86 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Y.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Y.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicY.Body(Qubit target) { this.CheckQubit(target); - Y(this.Id, (uint)target.Id); + Y((uint)target.Id); } void IIntrinsicY.ControlledBody(IQArray controls, Qubit target) @@ -21,7 +21,7 @@ void IIntrinsicY.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicY)this).Body(target), - (count, ids) => MCY(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCY(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Z.cs b/src/Simulation/Simulators/CommonNativeSimulator/Z.cs similarity index 78% rename from src/Simulation/Simulators/QuantumSimulator/Z.cs rename to src/Simulation/Simulators/CommonNativeSimulator/Z.cs index 026f4f5c6d2..aca4aade2e6 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Z.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/Z.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator + public partial class CommonNativeSimulator { void IIntrinsicZ.Body(Qubit target) { this.CheckQubit(target); - Z(this.Id, (uint)target.Id); + Z((uint)target.Id); } void IIntrinsicZ.ControlledBody(IQArray controls, Qubit target) @@ -21,7 +21,7 @@ void IIntrinsicZ.ControlledBody(IQArray controls, Qubit target) SafeControlled(controls, () => ((IIntrinsicZ)this).Body(target), - (count, ids) => MCZ(this.Id, count, ids, (uint)target.Id)); + (count, ids) => MCZ(count, ids, (uint)target.Id)); } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/Dump.cs b/src/Simulation/Simulators/QuantumSimulator/Dump.cs index d57d0b7dd4a..3e414204905 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Dump.cs +++ b/src/Simulation/Simulators/QuantumSimulator/Dump.cs @@ -1,8 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; -using System.IO; +using System.Diagnostics; +using System.Collections.Generic; using System.Linq; using Microsoft.Quantum.Simulation.Core; @@ -11,93 +12,33 @@ namespace Microsoft.Quantum.Simulation.Simulators public partial class QuantumSimulator { /// - /// Dumps the wave function for the given qubits into the given target. - /// If the target is QVoid or an empty string, it dumps it to the console - /// using the `Message` function, otherwise it dumps the content into a file - /// with the given name. - /// If the given qubits is null, it dumps the entire wave function, otherwise - /// it attemps to create the wave function or the resulting subsystem; if it fails - /// because the qubits are entangled with some external qubit, it just generates a message. + /// Returns the list of the qubits' ids currently allocated in the simulator. /// - protected virtual QVoid Dump(T target, IQArray? qubits = null) + public uint[] QubitIds { - var filename = (target is QVoid) ? "" : target.ToString(); - - QVoid process(Action channel) + get { - var ids = qubits?.Select(q => (uint)q.Id).ToArray() ?? QubitIds; - - var dumper = new SimpleDumper(this, channel); - channel($"# wave function for qubits with ids (least to most significant): {string.Join(";", ids)}"); - - if (!dumper.Dump(qubits)) - { - channel("## Qubits were entangled with an external qubit. Cannot dump corresponding wave function. ##"); - } - - return QVoid.Instance; - } - - var logMessage = this.Get, Microsoft.Quantum.Intrinsic.Message>(); - - // If no file provided, use `Message` to generate the message into the console; - if (string.IsNullOrWhiteSpace(filename)) - { - var op = this.Get, Microsoft.Quantum.Intrinsic.Message>(); - return process((msg) => op.Apply(msg)); - } - else - { - try - { - using (var file = new StreamWriter(filename)) - { - return process(file.WriteLine); - } - } - catch (Exception e) - { - logMessage.Apply($"[warning] Unable to write state to '{filename}' ({e.Message})"); - return QVoid.Instance; - } + var ids = new List(); + sim_QubitsIdsNative(this.Id, ids.Add); + Debug.Assert(this.QubitManager != null); + Debug.Assert(ids.Count == this.QubitManager.AllocatedQubitsCount); + return ids.ToArray(); } } - public class QsimDumpMachine : Quantum.Diagnostics.DumpMachine + protected override QVoid process(Action channel, IQArray? qubits) { - private QuantumSimulator Simulator { get; } + var ids = qubits?.Select(q => (uint)q.Id).ToArray() ?? QubitIds; - public QsimDumpMachine(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func __Body__ => (location) => - { - if (location == null) { throw new ArgumentNullException(nameof(location)); } - - return Simulator.Dump(location); - }; - } + var dumper = new SimpleDumper(this, channel); + channel($"# wave function for qubits with ids (least to most significant): {string.Join(";", ids)}"); - public class QSimDumpRegister : Quantum.Diagnostics.DumpRegister - { - private QuantumSimulator Simulator { get; } - - public QSimDumpRegister(QuantumSimulator m) : base(m) + if (!dumper.Dump(qubits)) { - this.Simulator = m; + channel("## Qubits were entangled with an external qubit. Cannot dump corresponding wave function. ##"); } - public override Func<(T, IQArray), QVoid> __Body__ => (__in) => - { - var (location, qubits) = __in; - - if (location == null) { throw new ArgumentNullException(nameof(location)); } - Simulator.CheckAndPreserveQubits(qubits); - - return Simulator.Dump(location, qubits); - }; + return QVoid.Instance; } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/NativeImports.cs b/src/Simulation/Simulators/QuantumSimulator/NativeImports.cs index 30b84a41e8d..dd77a4299d0 100644 --- a/src/Simulation/Simulators/QuantumSimulator/NativeImports.cs +++ b/src/Simulation/Simulators/QuantumSimulator/NativeImports.cs @@ -9,90 +9,106 @@ namespace Microsoft.Quantum.Simulation.Simulators { public partial class QuantumSimulator { + public const string QSIM_DLL_NAME = "Microsoft.Quantum.Simulator.Runtime"; // If this is not public then + // we get a CI build error: + // Preparation\Arbitrary.cs(23,41): error CS0117: 'QuantumSimulator' does not contain a definition for + // 'QSIM_DLL_NAME' [D:\a\1\s\submodules\QuantumLibraries\Standard\src\Standard.csproj] + + private delegate void IdsCallback(uint id); + [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "DumpIds")] + private static extern void sim_QubitsIdsNative(uint id, IdsCallback callback); + + [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "init")] + private static extern uint InitNative(); + + [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy")] + private static extern uint DestroyNative(uint id); + + [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "seed")] + private static extern void SetSeedNative(uint id, UInt32 seedValue); + [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "allocateQubit")] - private static extern void AllocateOne(uint id, uint qubit_id); + private static extern void AllocateOneNative(uint id, uint qubit_id); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "release")] - private static extern bool ReleaseOne(uint id, uint qubit_id); + private static extern bool ReleaseOneNative(uint id, uint qubit_id); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Exp")] - private static extern void Exp(uint id, uint n, Pauli[] paulis, double angle, uint[] ids); + private static extern void ExpNative(uint id, uint n, Pauli[] paulis, double angle, uint[] ids); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCExp")] - private static extern void MCExp(uint id, uint n, Pauli[] paulis, double angle, uint nc, uint[] ctrls, uint[] ids); + private static extern void MCExpNative(uint id, uint n, Pauli[] paulis, double angle, uint nc, uint[] ctrls, uint[] ids); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "H")] - private static extern void H(uint id, uint qubit); + private static extern void HNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCH")] - private static extern void MCH(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCHNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "M")] - private static extern uint M(uint id, uint q); + private static extern uint MNative(uint id, uint q); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Measure")] - private static extern uint Measure(uint id, uint n, Pauli[] b, uint[] ids); + private static extern uint MeasureNative(uint id, uint n, Pauli[] b, uint[] ids); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "R")] - private static extern void R(uint id, Pauli basis, double angle, uint qubit); + private static extern void RNative(uint id, Pauli basis, double angle, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCR")] - private static extern void MCR(uint id, Pauli basis, double angle, uint count, uint[] ctrls, uint qubit); + private static extern void MCRNative(uint id, Pauli basis, double angle, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "S")] - private static extern void S(uint id, uint qubit); + private static extern void SNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "AdjS")] - private static extern void AdjS(uint id, uint qubit); + private static extern void AdjSNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCS")] - private static extern void MCS(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCSNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCAdjS")] - private static extern void MCAdjS(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCAdjSNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "T")] - private static extern void T(uint id, uint qubit); + private static extern void TNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "AdjT")] - private static extern void AdjT(uint id, uint qubit); + private static extern void AdjTNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCT")] - private static extern void MCT(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCTNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCAdjT")] - private static extern void MCAdjT(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCAdjTNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "X")] - private static extern void X(uint id, uint qubit); + private static extern void XNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCX")] - private static extern void MCX(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCXNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Y")] - private static extern void Y(uint id, uint qubit); + private static extern void YNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCY")] - private static extern void MCY(uint id, uint count, uint[] ctrls, uint qubit); + private static extern void MCYNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Z")] - private static extern void Z(uint id, uint qubit); + private static extern void ZNative(uint id, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MCZ")] - private static extern void MCZ(uint id, uint count, uint[] ctrls, uint qubit); - - private delegate bool DumpCallback(uint idx, double real, double img); + private static extern void MCZNative(uint id, uint count, uint[] ctrls, uint qubit); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Dump")] - private static extern void sim_Dump(uint id, DumpCallback callback); + private static extern void sim_DumpNative(uint id, DumpCallback callback); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "DumpQubits")] - private static extern bool sim_DumpQubits(uint id, uint cout, uint[] ids, DumpCallback callback); + private static extern bool sim_DumpQubitsNative(uint id, uint cout, uint[] ids, DumpCallback callback); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "JointEnsembleProbability")] - private static extern double JointEnsembleProbability(uint id, uint n, Pauli[] b, uint[] q); + private static extern double JointEnsembleProbabilityNative(uint id, uint n, Pauli[] b, uint[] q); [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "random_choice")] - private static extern Int64 random_choice(uint id, Int64 size, double[] p); + private static extern Int64 random_choiceNative(uint id, Int64 size, double[] p); } } \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumSimulator/NativeWrappers.cs b/src/Simulation/Simulators/QuantumSimulator/NativeWrappers.cs new file mode 100644 index 00000000000..b185f287771 --- /dev/null +++ b/src/Simulation/Simulators/QuantumSimulator/NativeWrappers.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + + +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.Simulators +{ + public partial class QuantumSimulator + { + protected override void MCX(uint count, uint[] ctrls, uint qubit) + { + MCXNative(this.Id, count, ctrls, qubit); + } + + protected override void MCZ(uint count, uint[] ctrls, uint qubit) + { + MCZNative(this.Id, count, ctrls, qubit); + } + + protected override void H(uint qubit) + { + HNative(this.Id, qubit); + } + protected override void MCH(uint count, uint[] ctrls, uint qubit) + { + MCHNative(this.Id, count, ctrls, qubit); + } + + protected override void R(Pauli basis, double angle, uint qubit) + { + RNative(this.Id, basis, angle, qubit); + } + + protected override void S(uint qubit) + { + SNative(this.Id, qubit); + } + + protected override void AdjS(uint qubit) + { + AdjSNative(this.Id, qubit); + } + + protected override void T(uint qubit) + { + TNative(this.Id, qubit); + } + + protected override void AdjT(uint qubit) + { + AdjTNative(this.Id, qubit); + } + + protected override void X(uint qubit) + { + XNative(this.Id, qubit); + } + + protected override void Y(uint qubit) + { + YNative(this.Id, qubit); + } + + protected override void Z(uint qubit) + { + ZNative(this.Id, qubit); + } + + protected override double JointEnsembleProbability(uint n, Pauli[] b, uint[] q) + { + return JointEnsembleProbabilityNative(this.Id, n, b, q); + } + + protected override void Exp(uint n, Pauli[] paulis, double angle, uint[] ids) + { + ExpNative(this.Id, n, paulis, angle, ids); + } + + protected override void MCExp(uint n, Pauli[] paulis, double angle, uint nc, uint[] ctrls, uint[] ids) + { + MCExpNative(this.Id, n, paulis, angle, nc, ctrls, ids); + } + + protected override uint M(uint q) + { + return MNative(this.Id, q); + } + + protected override uint Measure(uint n, Pauli[] b, uint[] ids) + { + return MeasureNative(this.Id, n, b, ids); + } + + protected override void MCR(Pauli basis, double angle, uint count, uint[] ctrls, uint qubit) + { + MCRNative(this.Id, basis, angle, count, ctrls, qubit); + } + + protected override void MCS(uint count, uint[] ctrls, uint qubit) + { + MCSNative(this.Id, count, ctrls, qubit); + } + + protected override void MCAdjS(uint count, uint[] ctrls, uint qubit) + { + MCAdjSNative(this.Id, count, ctrls, qubit); + } + + protected virtual void sim_Dump(DumpCallback callback) + { + sim_DumpNative(this.Id, callback); + } + + protected virtual bool sim_DumpQubits(uint count, uint[] ids, DumpCallback callback) + { + return sim_DumpQubitsNative(this.Id, count, ids, callback); + } + + protected override void MCT(uint count, uint[] ctrls, uint qubit) + { + MCTNative(this.Id, count, ctrls, qubit); + } + + protected override void MCAdjT(uint count, uint[] ctrls, uint qubit) + { + MCAdjTNative(this.Id, count, ctrls, qubit); + } + + protected override void MCY(uint count, uint[] ctrls, uint qubit) + { + MCYNative(this.Id, count, ctrls, qubit); + } + + protected override void AllocateOne(uint qubit_id) + { + AllocateOneNative(this.Id, qubit_id); + } + protected override bool ReleaseOne(uint qubit_id) + { + return ReleaseOneNative(this.Id, qubit_id); + } + + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs index 2df2bae2bb7..58bceb2903f 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs @@ -12,24 +12,8 @@ namespace Microsoft.Quantum.Simulation.Simulators { - public partial class QuantumSimulator : SimulatorBase, IQSharpCore, IType1Core, IType2Core, IType3Core, IDisposable + public partial class QuantumSimulator : CommonNativeSimulator { - public const string QSIM_DLL_NAME = "Microsoft.Quantum.Simulator.Runtime"; - - private delegate void IdsCallback(uint id); - - [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "DumpIds")] - private static extern void sim_QubitsIds(uint id, IdsCallback callback); - - [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "init")] - private static extern uint Init(); - - [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy")] - private static extern uint Destroy(uint id); - - [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "seed")] - private static extern void SetSeed(uint id, UInt32 seedValue); - /// /// Creates a an instance of a quantum simulator. /// @@ -40,186 +24,27 @@ public QuantumSimulator( bool throwOnReleasingQubitsNotInZeroState = true, UInt32? randomNumberGeneratorSeed = null, bool disableBorrowing = false) - : base( - new QSimQubitManager(throwOnReleasingQubitsNotInZeroState, disableBorrowing : disableBorrowing), - (int?)randomNumberGeneratorSeed - ) + : base(throwOnReleasingQubitsNotInZeroState, + randomNumberGeneratorSeed, + disableBorrowing) { - Id = Init(); + Id = InitNative(); // Make sure that the same seed used by the built-in System.Random // instance is also used by the native simulator itself. - SetSeed(this.Id, (uint)this.Seed); - ((QSimQubitManager)QubitManager).Init(Id); - } - - public uint Id { get; } - - public override string Name - { - get - { - return "Quantum Simulator"; - } - } - - static void CheckQubitInUse(Qubit q, bool[] used) - { - if (q == null) throw new ArgumentNullException(nameof(q), "Trying to perform a primitive operation on a null Qubit"); - - if (used[q.Id]) - { - throw new NotDistinctQubits(q); - } - - used[q.Id] = true; - } - - /// - /// Makes sure the angle for a rotation or exp operation is not NaN or Infinity. - /// - static void CheckAngle(double angle) - { - IgnorableAssert.Assert(!(double.IsNaN(angle) || double.IsInfinity(angle)), "Invalid angle for rotation/exponentiation."); - - if (double.IsNaN(angle)) throw new ArgumentOutOfRangeException("angle", "Angle can't be NaN."); - if (double.IsInfinity(angle)) throw new ArgumentOutOfRangeException("angle", "Angle can't be Infity."); - } - - /// - /// Makes sure the target qubit of an operation is valid. In particular it checks that the qubit instance is not null. - /// Also sets the isMeasured flag to false for each qubit - /// - void CheckQubit(Qubit q1) - { - if (q1 == null) throw new ArgumentNullException(nameof(q1), "Trying to perform a primitive operation on a null Qubit"); - //setting qubit as not measured to not allow release in case of gate operation on qubit - q1.IsMeasured = false; - } - - /// - /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that - /// - none of the qubits are null - /// - there are no duplicated qubits - /// Also sets the isMeasured flag to false for each qubit - /// - bool[] CheckQubits(IQArray ctrls, Qubit q1) - { - bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; - - CheckQubitInUse(q1, used); - q1.IsMeasured = false; - - if (ctrls != null && ctrls.Length > 0) - { - foreach (var q in ctrls) - { - CheckQubitInUse(q, used); - //setting qubit as not measured to not allow release in case of gate operation on qubit - q.IsMeasured = false; - } - } - - return used; + SetSeedNative(this.Id, (uint)this.Seed); } - - /// - /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that - /// - none of the qubits are null - /// - there are no duplicated qubits - /// Also sets the isMeasured flag to false for each qubit - /// - bool[] CheckQubits(IQArray targets) + public override void Dispose() { - if (targets == null) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on a null Qubit array."); - if (targets.Length == 0) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on an empty Qubit array."); - - bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; - - foreach (var q in targets) - { - CheckQubitInUse(q, used); - //setting qubit as not measured to not allow release in case of gate operation on qubit - q.IsMeasured = false; - } - - return used; + DestroyNative(this.Id); } - /// - /// Intended to be used with simulator functions like Dump, Assert, AssertProb - /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that - /// - none of the qubits are null - /// - there are no duplicated qubits - /// - bool[] CheckAndPreserveQubits(IQArray targets) - { - if (targets == null) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on a null Qubit array."); - if (targets.Length == 0) throw new ArgumentNullException(nameof(targets), "Trying to perform an intrinsic operation on an empty Qubit array."); - - bool[] used = new bool[((QSimQubitManager)QubitManager).MaxId]; - - foreach (var q in targets) - { - CheckQubitInUse(q, used); - } - - return used; - } - - /// - /// Makes sure all qubits are valid as parameter of an intrinsic quantum operation. In particular it checks that - /// - none of the qubits are null - /// - there are no duplicated qubits - /// Also sets the isMeasured flag to false for each qubit - /// - bool[] CheckQubits(IQArray ctrls, IQArray targets) - { - bool[] used = CheckQubits(targets); - - if (ctrls != null) - { - foreach (var q in ctrls) - { - CheckQubitInUse(q, used); - //setting qubit as not measured to not allow release in case of gate operation on qubit - q.IsMeasured = false; - } - } - - return used; - } - - /// - /// Returns the list of the qubits' ids currently allocated in the simulator. - /// - public uint[] QubitIds + public override string Name { get { - var ids = new List(); - sim_QubitsIds(this.Id, ids.Add); - Debug.Assert(ids.Count == this.QubitManager.AllocatedQubitsCount); - return ids.ToArray(); + return "Quantum Simulator"; // There is a test case that expects exactly this string literal. } } - - static void SafeControlled(IQArray ctrls, Action noControlsAction, Action controlledAction) - { - if (ctrls == null || ctrls.Length == 0) - { - noControlsAction(); - } - else - { - uint count = (uint)ctrls.Length; - controlledAction(count, ctrls.GetIds()); - } - } - - public void Dispose() - { - Destroy(this.Id); - } } } diff --git a/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs b/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs index a7c351fad69..22c42a05f6e 100644 --- a/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs +++ b/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs @@ -2,19 +2,22 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.Simulators { public partial class QuantumSimulator { + protected delegate bool DumpCallback(uint idx, double real, double img); + /// /// This class allows you to dump the state (wave function) /// of the QuantumSimulator into a callback function. /// The callback function is triggered for every state basis /// vector in the wavefunction. /// - public abstract class StateDumper + public abstract class StateDumper // Is used by "iqsharp\src\Jupyter\Visualization\StateDisplayOperations.cs". { /// /// Basic constructor. Takes the simulator to probe. @@ -48,13 +51,13 @@ public virtual bool Dump(IQArray? qubits = null) { if (qubits == null) { - sim_Dump(Simulator.Id, Callback); + this.Simulator.sim_Dump(Callback); return true; } else { var ids = qubits.GetIds(); - return sim_DumpQubits(Simulator.Id, (uint)ids.Length, ids, Callback); + return this.Simulator.sim_DumpQubits((uint)ids.Length, ids, Callback); } } } @@ -167,6 +170,8 @@ public override bool Callback(uint idx, double real, double img) public override bool Dump(IQArray? qubits = null) { + Debug.Assert(this.Simulator.QubitManager != null); + var count = qubits == null ? this.Simulator.QubitManager.AllocatedQubitsCount : qubits.Length; From 0c253ee542ee6a1f40a1736853f5f86e54917faf Mon Sep 17 00:00:00 2001 From: Robin Kuzmin <9372582+kuzminrobin@users.noreply.github.com> Date: Tue, 19 Oct 2021 16:11:36 -0700 Subject: [PATCH 2/2] Reverting the Allocate() change. (#857) --- src/Simulation/Common/QubitManager.cs | 31 ++++++++++++++++--- .../CommonNativeSimulator/QubitManager.cs | 11 ++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 0313b9fd732..9b5faffe20f 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -321,13 +321,13 @@ public void Disable(IQArray qubitsToDisable) /// Allocates a qubit. /// Returns null if the qubit cannot be allocated. /// - protected virtual Qubit Allocate(bool usedOnlyForBorrowing) + protected virtual Qubit? Allocate(bool usedOnlyForBorrowing) { if (free == None) { if (!MayExtendCapacity) { - throw new NotEnoughQubits(1, this.FreeQubitsCount); + return null; } long oldNumQubits = NumQubits; @@ -398,7 +398,12 @@ protected virtual Qubit Allocate(bool usedOnlyForBorrowing) /// public Qubit Allocate() { - return Allocate(usedOnlyForBorrowing: false); + Qubit? qb = Allocate(usedOnlyForBorrowing: false); + if (qb == null) + { + throw new NotEnoughQubits(1, this.FreeQubitsCount); + } + return qb; } /// @@ -424,7 +429,15 @@ public IQArray Allocate(long numToAllocate) } for (int i = 0; i < numToAllocate; i++) { - Qubit allocated = Allocate(usedOnlyForBorrowing: false); + Qubit? allocated = Allocate(usedOnlyForBorrowing: false); + if (allocated == null) + { + for (int k = 0; k < i; k++) + { + Release(result[k], wasUsedOnlyForBorrowing: false); + } + throw new NotEnoughQubits(numToAllocate, this.FreeQubitsCount); + } result.Modify(i, allocated); } @@ -581,7 +594,15 @@ internal IQArray Borrow(long numToBorrow, HashSet qubitsInUse) { // Not enough qubits to borrow. Allocate what was not borrowed. for (long i = numBorrowed; i < numToBorrow; i++) { - Qubit allocated = Allocate(usedOnlyForBorrowing: true); + Qubit? allocated = Allocate(usedOnlyForBorrowing: true); + if (allocated == null) + { + for (long k = numBorrowed; k < i; k++) + { + Release(borrowed[(int)k], wasUsedOnlyForBorrowing: true); + } + throw new NotEnoughQubits(numToBorrow, numBorrowed + this.FreeQubitsCount); + } borrowed.Modify(i, allocated); } } diff --git a/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs b/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs index c32ff84800d..4c1c9d73756 100644 --- a/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/QubitManager.cs @@ -42,11 +42,14 @@ public override Qubit CreateQubitObject(long id) return new QSimQubit((int)id, Simulator); } - protected override Qubit Allocate(bool usedOnlyForBorrowing) + protected override Qubit? Allocate(bool usedOnlyForBorrowing) { - Qubit qubit = base.Allocate(usedOnlyForBorrowing); - Debug.Assert(Simulator != null); - Simulator.AllocateOne((uint)qubit.Id); + Qubit? qubit = base.Allocate(usedOnlyForBorrowing); + if (qubit != null) + { + Debug.Assert(Simulator != null); + Simulator.AllocateOne((uint)qubit.Id); + } return qubit; }