From 3f152271d2e252be0b51cf7b513bf92ffbdbd89f Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 2 Sep 2020 08:47:43 -0700 Subject: [PATCH 01/20] abstrace and virtual members of SimulatorBase --- src/Simulation/Common/Extensions.cs | 2 +- src/Simulation/Common/{AbstractFactory.cs => Factory.cs} | 2 +- src/Simulation/Common/SimulatorBase.cs | 6 +++--- .../Simulators.Tests/QCTraceSimulatorPrimitivesTests.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/Simulation/Common/{AbstractFactory.cs => Factory.cs} (98%) diff --git a/src/Simulation/Common/Extensions.cs b/src/Simulation/Common/Extensions.cs index b36867a7388..22b14c4f7c3 100644 --- a/src/Simulation/Common/Extensions.cs +++ b/src/Simulation/Common/Extensions.cs @@ -30,7 +30,7 @@ public static uint[] GetIds(this IQArray qubits) /// a subclass of T and registers as the override of the BaseType /// it implements. /// - public static void InitBuiltinOperations(this AbstractFactory factory, Type t) + public static void InitBuiltinOperations(this Factory factory, Type t) { if (t == null) { diff --git a/src/Simulation/Common/AbstractFactory.cs b/src/Simulation/Common/Factory.cs similarity index 98% rename from src/Simulation/Common/AbstractFactory.cs rename to src/Simulation/Common/Factory.cs index 204936002ee..dcb945df692 100644 --- a/src/Simulation/Common/AbstractFactory.cs +++ b/src/Simulation/Common/Factory.cs @@ -16,7 +16,7 @@ namespace Microsoft.Quantum.Simulation.Common /// It also provides a mechanism to register overrides when a given /// type should be replaced by a subclass. /// - public abstract class AbstractFactory + public class Factory { private Dictionary opsOverrides = new Dictionary(); private Dictionary opsCache = new Dictionary(); diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index ffb9aef7f0c..8f5f2e3182f 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -19,7 +19,7 @@ namespace Microsoft.Quantum.Simulation.Common /// can be tied to this simulator) and /// to manage the allocation of Qubits (via the QubitManager). /// - public abstract class SimulatorBase : AbstractFactory, IOperationFactory + public abstract class SimulatorBase : Factory, IOperationFactory { public event Action? OnOperationStart = null; public event Action? OnOperationEnd = null; @@ -82,7 +82,7 @@ public SimulatorBase(IQubitManager? qubitManager = null, int? seed = null) } } - public virtual I Get(Type T) + public I Get(Type T) { return (I)this.GetInstance(T); } @@ -97,7 +97,7 @@ public virtual I Get(Type T) /// If the operation has no body in the Q# file, and no override has been defined in the Simulator, /// this method will throw an InvalidOperationException. /// - public virtual I Get() where T : AbstractCallable, I + public I Get() where T : AbstractCallable, I { var key = typeof(T); return (I)this.GetInstance(key); diff --git a/src/Simulation/Simulators.Tests/QCTraceSimulatorPrimitivesTests.cs b/src/Simulation/Simulators.Tests/QCTraceSimulatorPrimitivesTests.cs index 6b1767dc3e8..d9a15e1a27c 100644 --- a/src/Simulation/Simulators.Tests/QCTraceSimulatorPrimitivesTests.cs +++ b/src/Simulation/Simulators.Tests/QCTraceSimulatorPrimitivesTests.cs @@ -20,7 +20,7 @@ public PrimitivesTestsQuite(ITestOutputHelper output) this.output = output; } - private static void OverrideOperation(AbstractFactory sim) + private static void OverrideOperation(Factory sim) where TypeToOverrideBy : AbstractCallable, OperationType where TypeToOverride : AbstractCallable, OperationType { From 3f4427f160d09d5530d09dea85a57adc1550b6b4 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 2 Sep 2020 14:08:10 -0700 Subject: [PATCH 02/20] minor things --- src/Simulation/Common/QubitManager.cs | 21 +- .../Common/QubitManagerTrackingScope.cs | 2 +- src/Simulation/Core/Qubit.cs | 3 +- .../QCTraceSimulator/Circuits/Interface.qs | 362 +++++++++--------- .../QuantumSimulator/QubitManager.cs | 2 +- 5 files changed, 189 insertions(+), 201 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 9bc54dfce3d..9eb53782955 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Microsoft.Quantum.Intrinsic; using Microsoft.Quantum.Simulation.Core; using Microsoft.Quantum.Simulation.Simulators.Exceptions; @@ -31,8 +30,8 @@ public class QubitManager long numDisabledQubits; // Number of disabled qubits. // Options - bool MayExtendCapacity; - bool EncourageReuse; + readonly bool MayExtendCapacity; + readonly bool EncourageReuse; public bool DisableBorrowing { get; } const long MaxQubitCapacity = long.MaxValue - 3; @@ -233,18 +232,9 @@ protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing) return result; } - private class QubitNonAbstract : Qubit - { - // This class is only needed because Qubit is abstract. - // It is equivalent to Qubit and adds nothing to it except the ability to create it. - // It should be used only in CreateQubitObject below, and nowhere else. - // When Qubit stops being abstract, this class should be removed. - public QubitNonAbstract(int id) : base(id) { } - } - public virtual Qubit CreateQubitObject(long id) { // User may override it to create his own Qubit object of a derived type. - return new QubitNonAbstract((int)id); + return new Qubit((int)id); } /// @@ -490,13 +480,12 @@ protected virtual Qubit BorrowOneQubit(long id) private long TryBorrow(long numToBorrow, QArray result, IEnumerable excludedQubitsSortedById) { long curQubit = 0; - long numBorrowed = 0; long curBorrowed = 0; + long numBorrowed = System.Math.Min(GetQubitsAvailableToBorrowCount(excludedQubitsSortedById), numToBorrow); + IEnumerator enumer = excludedQubitsSortedById.GetEnumerator(); bool exclusionsPresent = enumer.MoveNext(); - numBorrowed = System.Math.Min(GetQubitsAvailableToBorrowCount(excludedQubitsSortedById), numToBorrow); - while (curBorrowed < numBorrowed) { while (IsFree(curQubit) || IsDisabled(curQubit)) diff --git a/src/Simulation/Common/QubitManagerTrackingScope.cs b/src/Simulation/Common/QubitManagerTrackingScope.cs index a166f98bfa0..5cd72c8fa05 100644 --- a/src/Simulation/Common/QubitManagerTrackingScope.cs +++ b/src/Simulation/Common/QubitManagerTrackingScope.cs @@ -41,7 +41,7 @@ public List Locals } } - private Stack operationStack; // Stack of operation calls. + private readonly Stack operationStack; // Stack of operation calls. private StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. public QubitManagerTrackingScope( diff --git a/src/Simulation/Core/Qubit.cs b/src/Simulation/Core/Qubit.cs index ec1e0d40125..5681b0f5947 100644 --- a/src/Simulation/Core/Qubit.cs +++ b/src/Simulation/Core/Qubit.cs @@ -5,14 +5,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; namespace Microsoft.Quantum.Simulation.Core { /// /// Represents a Quantum Bit. /// - public abstract class Qubit : IApplyData, IEquatable, IEqualityComparer + public class Qubit : IApplyData, IEquatable, IEqualityComparer { [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static readonly Qubit[] NO_QUBITS = new Qubit[0]; diff --git a/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs b/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs index 3f69a55bd11..c9e947a5175 100644 --- a/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs +++ b/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs @@ -1,183 +1,183 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Simulation.Simulators.QCTraceSimulators.Implementation { - - /// # Summary - /// Controlled-X gate natively supported by the machine - /// - /// # Input - /// ## control - /// the qubit used to control the application of X gate - /// ## target - /// the qubit to which Pauli X is applied when control qubit is in state |1⟩ - /// - /// # Remarks - /// Controlled-X gate with target on qubit 2 and control on qubit 1 - /// is C₁X₂ = [ [1,0,0,0], [0,1,0,0], [0,0,0,1], [0,0,1,0] ] - operation Interface_CX (control : Qubit, target : Qubit) : Unit { - body intrinsic; - } - - /// # Summary - /// R gate natively supported by the machine. It is exp(-iφP/2) where P is the Pauli matrix - /// - /// # Input - /// ## axis - /// Pauli matrix, P - /// ## angle - /// Rotation angle, φ - /// ## target - /// the qubit operation is acting on - operation Interface_R (axis : Pauli, angle : Double, target : Qubit) : Unit { - body intrinsic; - } - - /// # Summary - /// RzFrac gate natively supported by the machine. It is exp(iπkP/2ⁿ) where P is the Pauli matrix - /// - /// # Input - /// ## axis - /// Pauli matrix, P - /// ## numerator - /// k - /// ## power - /// n - /// ## target - /// the qubit operation is acting on - /// - /// # Remarks - /// When power is 3 or less the operation is guaranteed to use S and T and Z gates to perform rotation - operation Interface_RFrac (axis : Pauli, numerator : Int, power : Int, target : Qubit) : Unit { - body intrinsic; - } - - /// # Summary - /// Applies Clifford multiplied by a pauli matrix - /// given by 'pauli' to the qubit given by 'target' - /// - /// # Input - /// ## cliffordId - /// Id of the single qubit unitary to apply. See remarks - /// - /// # Remarks - /// The list of id's corresponding to Cliffords is given by: - /// Identity - 0 - /// H - 1 - /// S - 2 - /// H followed by S ( as circuit ) - 3 - /// S followed by H ( as circuit ) - 4 - /// H S H - 5 - operation Interface_Clifford (cliffordId : Int, pauli : Pauli, target : Qubit) : Unit { - body intrinsic; - } - - - /// Forces the future measurement of a given observable to give specified result - operation ForceMeasure (observable : Pauli[], target : Qubit[], result : Result) : Unit { - body intrinsic; - } - - /// - /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. - /// - operation Interface_ApplyIfElse ( - measurementResult : Result, - onResultZeroOp : (Unit => Unit), - onResultOneOp : (Unit => Unit) - ) : Unit { +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.Simulators.QCTraceSimulators.Implementation { + + /// # Summary + /// Controlled-X gate natively supported by the machine + /// + /// # Input + /// ## control + /// the qubit used to control the application of X gate + /// ## target + /// the qubit to which Pauli X is applied when control qubit is in state |1⟩ + /// + /// # Remarks + /// Controlled-X gate with target on qubit 2 and control on qubit 1 + /// is C₁X₂ = [ [1,0,0,0], [0,1,0,0], [0,0,0,1], [0,0,1,0] ] + operation Interface_CX (control : Qubit, target : Qubit) : Unit { body intrinsic; - } - - /// - /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. - /// onReusltZeroOp and onResultOneOp must both be adjointable. - /// - operation Interface_ApplyIfElseA ( - measurementResult : Result, - onResultZeroOp : (Unit => Unit is Adj), - onResultOneOp : (Unit => Unit is Adj) - ) : Unit is Adj { - body intrinsic; - } - - /// - /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. - /// onReusltZeroOp and onResultOneOp must both be controllable. - /// - operation Interface_ApplyIfElseC ( - measurementResult : Result, - onResultZeroOp : (Unit => Unit is Ctl), - onResultOneOp : (Unit => Unit is Ctl) - ) : Unit is Ctl { - body intrinsic; - } - - /// - /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. - /// onReusltZeroOp and onResultOneOp must both be controllable and adjointable. - /// - operation Interface_ApplyIfElseCA ( - measurementResult : Result, - onResultZeroOp : (Unit => Unit is Ctl + Adj), - onResultOneOp : (Unit => Unit is Ctl + Adj) - ) : Unit is Adj + Ctl { - body intrinsic; - } - - /// - /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding - /// element of resultsValues, else performs onNonEqualOp. - /// - operation Interface_ApplyConditionally ( - measurementResults : Result[], - resultsValues : Result[], - onEqualOp : (Unit => Unit), - onNonEqualOp : (Unit => Unit) - ) : Unit { + } + + /// # Summary + /// R gate natively supported by the machine. It is exp(-iφP/2) where P is the Pauli matrix + /// + /// # Input + /// ## axis + /// Pauli matrix, P + /// ## angle + /// Rotation angle, φ + /// ## target + /// the qubit operation is acting on + operation Interface_R (axis : Pauli, angle : Double, target : Qubit) : Unit { body intrinsic; - } - - /// - /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding - /// element of resultsValues, else performs onNonEqualOp. - /// onEqualOp and onNonEqualOp must both be adjointable. - /// - operation Interface_ApplyConditionallyA ( - measurementResults : Result[], - resultsValues : Result[], - onEqualOp : (Unit => Unit is Adj), - onNonEqualOp : (Unit => Unit is Adj) - ) : Unit is Adj { - body intrinsic; - } - - /// - /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding - /// element of resultsValues, else performs onNonEqualOp. - /// onEqualOp and onNonEqualOp must both be controllable. - /// - operation Interface_ApplyConditionallyC ( - measurementResults : Result[], - resultsValues : Result[], - onEqualOp : (Unit => Unit is Ctl), - onNonEqualOp : (Unit => Unit is Ctl) - ) : Unit is Ctl { - body intrinsic; - } - - /// - /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding - /// element of resultsValues, else performs onNonEqualOp. - /// onEqualOp and onNonEqualOp must both be controllable and adjointable. - /// - operation Interface_ApplyConditionallyCA ( - measurementResults : Result[], - resultsValues : Result[], - onEqualOp : (Unit => Unit is Ctl + Adj), - onNonEqualOp : (Unit => Unit is Ctl + Adj) - ) : Unit is Adj + Ctl { - body intrinsic; - } - -} + } + + /// # Summary + /// RzFrac gate natively supported by the machine. It is exp(iπkP/2ⁿ) where P is the Pauli matrix + /// + /// # Input + /// ## axis + /// Pauli matrix, P + /// ## numerator + /// k + /// ## power + /// n + /// ## target + /// the qubit operation is acting on + /// + /// # Remarks + /// When power is 3 or less the operation is guaranteed to use S and T and Z gates to perform rotation + operation Interface_RFrac (axis : Pauli, numerator : Int, power : Int, target : Qubit) : Unit { + body intrinsic; + } + + /// # Summary + /// Applies Clifford multiplied by a pauli matrix + /// given by 'pauli' to the qubit given by 'target' + /// + /// # Input + /// ## cliffordId + /// Id of the single qubit unitary to apply. See remarks + /// + /// # Remarks + /// The list of id's corresponding to Cliffords is given by: + /// Identity - 0 + /// H - 1 + /// S - 2 + /// H followed by S ( as circuit ) - 3 + /// S followed by H ( as circuit ) - 4 + /// H S H - 5 + operation Interface_Clifford (cliffordId : Int, pauli : Pauli, target : Qubit) : Unit { + body intrinsic; + } + + + /// Forces the future measurement of a given observable to give specified result + operation ForceMeasure (observable : Pauli[], target : Qubit[], result : Result) : Unit { + body intrinsic; + } + + /// + /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. + /// + operation Interface_ApplyIfElse ( + measurementResult : Result, + onResultZeroOp : (Unit => Unit), + onResultOneOp : (Unit => Unit) + ) : Unit { + body intrinsic; + } + + /// + /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. + /// onReusltZeroOp and onResultOneOp must both be adjointable. + /// + operation Interface_ApplyIfElseA ( + measurementResult : Result, + onResultZeroOp : (Unit => Unit is Adj), + onResultOneOp : (Unit => Unit is Adj) + ) : Unit is Adj { + body intrinsic; + } + + /// + /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. + /// onReusltZeroOp and onResultOneOp must both be controllable. + /// + operation Interface_ApplyIfElseC ( + measurementResult : Result, + onResultZeroOp : (Unit => Unit is Ctl), + onResultOneOp : (Unit => Unit is Ctl) + ) : Unit is Ctl { + body intrinsic; + } + + /// + /// Performs the onResultZeroOp when measurementResult is Zero, else performs the onResultOneOp. + /// onReusltZeroOp and onResultOneOp must both be controllable and adjointable. + /// + operation Interface_ApplyIfElseCA ( + measurementResult : Result, + onResultZeroOp : (Unit => Unit is Ctl + Adj), + onResultOneOp : (Unit => Unit is Ctl + Adj) + ) : Unit is Adj + Ctl { + body intrinsic; + } + + /// + /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding + /// element of resultsValues, else performs onNonEqualOp. + /// + operation Interface_ApplyConditionally ( + measurementResults : Result[], + resultsValues : Result[], + onEqualOp : (Unit => Unit), + onNonEqualOp : (Unit => Unit) + ) : Unit { + body intrinsic; + } + + /// + /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding + /// element of resultsValues, else performs onNonEqualOp. + /// onEqualOp and onNonEqualOp must both be adjointable. + /// + operation Interface_ApplyConditionallyA ( + measurementResults : Result[], + resultsValues : Result[], + onEqualOp : (Unit => Unit is Adj), + onNonEqualOp : (Unit => Unit is Adj) + ) : Unit is Adj { + body intrinsic; + } + + /// + /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding + /// element of resultsValues, else performs onNonEqualOp. + /// onEqualOp and onNonEqualOp must both be controllable. + /// + operation Interface_ApplyConditionallyC ( + measurementResults : Result[], + resultsValues : Result[], + onEqualOp : (Unit => Unit is Ctl), + onNonEqualOp : (Unit => Unit is Ctl) + ) : Unit is Ctl { + body intrinsic; + } + + /// + /// Performs the onEqualOp when each element of measurementResults is equal to the corresponding + /// element of resultsValues, else performs onNonEqualOp. + /// onEqualOp and onNonEqualOp must both be controllable and adjointable. + /// + operation Interface_ApplyConditionallyCA ( + measurementResults : Result[], + resultsValues : Result[], + onEqualOp : (Unit => Unit is Ctl + Adj), + onNonEqualOp : (Unit => Unit is Ctl + Adj) + ) : Unit is Adj + Ctl { + body intrinsic; + } + +} diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs index 7b45f3f9ba4..2c60924ae16 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs @@ -13,7 +13,7 @@ public partial class QuantumSimulator { class QSimQubitManager : QubitManagerTrackingScope { - bool throwOnReleasingQubitsNotInZeroState; + readonly bool throwOnReleasingQubitsNotInZeroState; [DllImport(QSIM_DLL_NAME, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, EntryPoint = "allocateQubit")] private static extern void AllocateOne(uint id, uint qubit_id); From 286dd03de6634466cefcc26cc0872016e5dfb6f5 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 2 Sep 2020 15:34:20 -0700 Subject: [PATCH 03/20] unifying qubit managers --- src/Simulation/Common/QubitManager.cs | 363 ++++++++++++------ .../Common/QubitManagerTrackingScope.cs | 208 ---------- src/Simulation/Core/Qubit.cs | 2 +- .../QCTraceSimulator/TraceableQubitManager.cs | 2 +- .../Simulators.Tests/QubitManagerTests.cs | 6 +- .../Simulators.Tests/TrivialSimulator.cs | 2 +- .../QuantumProcessorDispatcher.cs | 2 +- .../QuantumSimulator/QubitManager.cs | 2 +- .../ToffoliSimulator/ToffoliSimulator.cs | 2 +- 9 files changed, 257 insertions(+), 332 deletions(-) delete mode 100644 src/Simulation/Common/QubitManagerTrackingScope.cs diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 9eb53782955..5eeb7de4875 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -16,7 +16,7 @@ namespace Microsoft.Quantum.Simulation.Common /// Allocation and release are O(1) operations. /// QubitManager uses memory - sizeof(long)*qubitCapacity. qubitCapacity is passed in to the constructor. /// - public class QubitManager + public class QubitManager : IQubitManager { long NumQubits; // Total number of qubits this QubitManager is capable of handling. long None; // Indicates the end of the list of free qubits. If we reach it - we are out of qubits. @@ -48,6 +48,94 @@ public class QubitManager // For qubits that are free, the array stores the index of the next free qubit (a value less than "Allocated" constant). // The last free qubit in the list of free qubits stores the value "None". + // stack frame management needed to support borrowing qubits + #region StackFrameManagement + + private class StackFrame + { + internal IApplyData Data; + internal IEnumerable QubitsInArgument => Data?.Qubits; + internal List _locals; // Qubits allocated/borrowed in the current operation + + public StackFrame() + { + Data = null; + } + + public StackFrame(IApplyData data) + { + Data = data; + } + + public List Locals + { + get + { + if (_locals == null) + { + _locals = new List(); + } + + return _locals; + } + } + } + + private readonly Stack operationStack; // Stack of operation calls. + private StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. + + public void OnOperationStart(ICallable _, IApplyData values) + { + if (!DisableBorrowing) + { + operationStack.Push(curFrame); + curFrame = new StackFrame(values); + } + } + + public void OnOperationEnd(ICallable _, IApplyData values) + { + if (!DisableBorrowing) + { + curFrame = operationStack.Pop(); + } + } + + private IEnumerable ConstructExcludedQubitsArray(StackFrame frame) + { + if (DisableBorrowing || frame == null) + { + return Qubit.NO_QUBITS; + } + + var qubitsInArgument = frame.QubitsInArgument?.ToArray(); + long numExcluded = frame.Locals.Count + (qubitsInArgument?.Length ?? 0); + var excludedQubits = new Qubit[numExcluded]; + + int k = 0; + if (qubitsInArgument != null) + { + foreach (Qubit q in qubitsInArgument) + { + excludedQubits[k] = q; + k++; + } + } + foreach (Qubit q in frame.Locals) + { + excludedQubits[k] = q; + k++; + } + Debug.Assert(k == numExcluded); + + // The following is not really efficient, but let's wait to see if distinct can be part of the contract + // for the qubitsInArgument parameter of StartOperation call. + // Well, we are talking about really small arrays here anyway. + return excludedQubits.Where(q => q != null).Distinct().OrderBy(Qubit => Qubit.Id); + } + + #endregion + /// /// Creates and initializes QubitManager that can handle up to numQubits qubits /// @@ -75,6 +163,35 @@ public QubitManager( freeTail = NumQubits - 1; numAllocatedQubits = 0; numDisabledQubits = 0; + + if (!DisableBorrowing) + { + operationStack = new Stack(); + curFrame = new StackFrame(); + } + } + + private class QubitNonAbstract : Qubit + { + // This class is only needed because Qubit is abstract. + // It is equivalent to Qubit and adds nothing to it except the ability to create it. + // It should be used only in CreateQubitObject below, and nowhere else. + // When Qubit stops being abstract, this class should be removed. + public QubitNonAbstract(int id) : base(id) { } + } + + /// + /// May be overriden to create a custom Qubit object of a derived type. + /// + /// unique qubit id + /// a newly instantiated qubit + public virtual Qubit CreateQubitObject(long id) + { + if (id >= Int32.MaxValue) + { + throw new NotSupportedException($"Qubit id out of range."); + } + return new QubitNonAbstract((int)id); } private void UpdateQubitCapacity(long newQubitCapacity) @@ -88,50 +205,6 @@ private void UpdateQubitCapacity(long newQubitCapacity) this.qubits = new long[NumQubits]; } - private void ExtendQubitArray() - { - long oldNumQubits = NumQubits; - long oldNone = None; - long oldAllocated = Allocated; - long oldDisabled = Disabled; - long oldAllocatedForBorrowing = AllocatedForBorrowing; - long[] oldQubitsArray = this.qubits; - - UpdateQubitCapacity(oldNumQubits*2); // This changes Allocated, Disabled, AllocatedForBorrowing markers. - - for (long i = 0; i < oldNumQubits; i++) - { - if (oldQubitsArray[i] == oldNone) { - // Point to the first new (free) element - this.qubits[i] = oldNumQubits; - } else if (oldQubitsArray[i] == oldAllocated) { - // Allocated qubits are marked differently now. - this.qubits[i] = Allocated; - } - else if (oldQubitsArray[i] == oldDisabled) - { - // Disabled qubits are marked differently now. - this.qubits[i] = Disabled; - } - else if (oldQubitsArray[i] >= oldAllocatedForBorrowing) { - // This updates refCounts - this.qubits[i] = (oldQubitsArray[i] - oldAllocatedForBorrowing) + AllocatedForBorrowing ; - } - } - - for (long i = oldNumQubits; i < NumQubits; i++) - { - this.qubits[i] = i + 1; - } - Debug.Assert(this.qubits[NumQubits - 1] == None); - - if (free == oldNone) - { - free = oldNumQubits; - freeTail = NumQubits - 1; - } - } - public bool IsValid(Qubit qubit) { if (qubit == null) { return false; } @@ -167,19 +240,6 @@ private bool IsAllocatedForBorrowing(long id) return qubits[id] >= AllocatedForBorrowing; } - // Returns true if qubit needs to be released: It has been allocated for borrowing and is not borrowed any more. - private bool BorrowingRefCountIsOne(long id) - { - if (IsAllocatedForBorrowing(id)) - { - if (qubits[id] == AllocatedForBorrowing) - { - return true; - } - } - return false; - } - // Returns true if qubit needs to be released: It has been allocated for borrowing and is not borrowed any more. private bool DecreaseBorrowingRefCount(long id) { @@ -199,14 +259,6 @@ private bool DecreaseBorrowingRefCount(long id) } } - private void IncreaseBorrowingRefCount(long id) - { - if (IsAllocatedForBorrowing(id)) - { - qubits[id]++; - } - } - /// /// Allocates a qubit. /// @@ -214,27 +266,68 @@ protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing) { if (free == None) { - if (MayExtendCapacity) + if (!MayExtendCapacity) { - ExtendQubitArray(); + return null; } - else + + long oldNumQubits = NumQubits; + long oldNone = None; + long oldAllocated = Allocated; + long oldDisabled = Disabled; + long oldAllocatedForBorrowing = AllocatedForBorrowing; + long[] oldQubitsArray = this.qubits; + + UpdateQubitCapacity(oldNumQubits * 2); // This changes Allocated, Disabled, AllocatedForBorrowing markers. + + for (long i = 0; i < oldNumQubits; i++) { - return null; + if (oldQubitsArray[i] == oldNone) + { + // Point to the first new (free) element + this.qubits[i] = oldNumQubits; + } + else if (oldQubitsArray[i] == oldAllocated) + { + // Allocated qubits are marked differently now. + this.qubits[i] = Allocated; + } + else if (oldQubitsArray[i] == oldDisabled) + { + // Disabled qubits are marked differently now. + this.qubits[i] = Disabled; + } + else if (oldQubitsArray[i] >= oldAllocatedForBorrowing) + { + // This updates refCounts + this.qubits[i] = (oldQubitsArray[i] - oldAllocatedForBorrowing) + AllocatedForBorrowing; + } + } + + for (long i = oldNumQubits; i < NumQubits; i++) + { + this.qubits[i] = i + 1; + } + Debug.Assert(this.qubits[NumQubits - 1] == None); + + if (free == oldNone) + { + free = oldNumQubits; + freeTail = NumQubits - 1; } } - Qubit result = CreateQubitObject(free); + + Qubit ret = CreateQubitObject(free); long temp = free; free = qubits[free]; qubits[temp] = (usedOnlyForBorrowing ? AllocatedForBorrowing : Allocated); numAllocatedQubits++; - return result; - } - - public virtual Qubit CreateQubitObject(long id) - { // User may override it to create his own Qubit object of a derived type. - return new Qubit((int)id); + if (!DisableBorrowing) + { + curFrame.Locals.Add(ret); + } + return ret; } /// @@ -323,6 +416,12 @@ protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) numAllocatedQubits--; Debug.Assert(numAllocatedQubits >= 0); } + + if (!DisableBorrowing) + { + bool success = curFrame.Locals.Remove(qubit); + Debug.Assert(success, "Releasing qubit that is not a local variable in scope."); + } } /// @@ -387,23 +486,29 @@ public virtual void Disable(IQArray qubitsToDisable) } - public long GetQubitsAvailableToBorrowCount(IEnumerable excludedQubitsSortedById) + public long GetQubitsAvailableToBorrowCount(IEnumerable excludedQubits) { // Note: this function is not allowed to call its no-parameters cousin: GetQubitsAvailableToBorrowCount() - return numAllocatedQubits - excludedQubitsSortedById.Count(); + return numAllocatedQubits - excludedQubits.Count(); } public virtual long GetQubitsAvailableToBorrowCount() { - return numAllocatedQubits; + return DisableBorrowing + ? 0 + : GetQubitsAvailableToBorrowCount(ConstructExcludedQubitsArray(curFrame)); } public virtual long GetParentQubitsAvailableToBorrowCount() { - return GetQubitsAvailableToBorrowCount(); + // The operationStack only contains "out" frames, but not the current frame. + // Thus, the top of the stack is the parent frame, not the current frame. + var parentFrame = operationStack.TryPeek(out StackFrame frame) ? frame : null; + return DisableBorrowing + ? 0 + : GetQubitsAvailableToBorrowCount(ConstructExcludedQubitsArray(parentFrame)); } - public long GetFreeQubitsCount() { return NumQubits - numDisabledQubits - numAllocatedQubits; @@ -422,6 +527,55 @@ public IEnumerable GetAllocatedIds() } } + #region Borrow + + protected virtual Qubit BorrowOneQubit(long id) + { + if (IsAllocatedForBorrowing(id)) + { + qubits[id]++; + } + + Qubit ret = CreateQubitObject(id); + if (!DisableBorrowing) + { + curFrame.Locals.Add(ret); + } + return ret; + } + + private long TryBorrow(long numToBorrow, QArray result, IEnumerable excludedQubitsSortedById) + { + long curQubit = 0; + long curBorrowed = 0; + long numBorrowed = System.Math.Min(GetQubitsAvailableToBorrowCount(excludedQubitsSortedById), numToBorrow); + + IEnumerator enumer = excludedQubitsSortedById.GetEnumerator(); + bool exclusionsPresent = enumer.MoveNext(); + + while (curBorrowed < numBorrowed) + { + while (IsFree(curQubit) || IsDisabled(curQubit)) + { + curQubit++; + Debug.Assert(curQubit < NumQubits); + } + Debug.Assert((!exclusionsPresent) || (enumer.Current.Id >= curQubit)); + if ((!exclusionsPresent) || (enumer.Current.Id != curQubit)) + { + result.Modify(curBorrowed, BorrowOneQubit(curQubit)); + curBorrowed++; + } + else + { + exclusionsPresent = enumer.MoveNext(); + } + curQubit++; + Debug.Assert(curQubit < NumQubits); + } + return numBorrowed; + } + /// /// Borrows a number of qubits. Chooses them from among already allocated ones. /// Makes sure borrowed qubits are not on the exclusion list. @@ -471,46 +625,25 @@ public IEnumerable GetAllocatedIds() return result; } - protected virtual Qubit BorrowOneQubit(long id) + public Qubit Borrow() { - IncreaseBorrowingRefCount(id); - return CreateQubitObject(id); + return this.Borrow(1, ConstructExcludedQubitsArray(curFrame))[0]; } - private long TryBorrow(long numToBorrow, QArray result, IEnumerable excludedQubitsSortedById) + public IQArray Borrow(long numToBorrow) { - long curQubit = 0; - long curBorrowed = 0; - long numBorrowed = System.Math.Min(GetQubitsAvailableToBorrowCount(excludedQubitsSortedById), numToBorrow); - - IEnumerator enumer = excludedQubitsSortedById.GetEnumerator(); - bool exclusionsPresent = enumer.MoveNext(); - - while (curBorrowed < numBorrowed) - { - while (IsFree(curQubit) || IsDisabled(curQubit)) - { - curQubit++; - Debug.Assert(curQubit < NumQubits); - } - Debug.Assert((!exclusionsPresent) || (enumer.Current.Id >= curQubit)); - if ((!exclusionsPresent) || (enumer.Current.Id != curQubit)) - { - result.Modify(curBorrowed, BorrowOneQubit(curQubit)); - curBorrowed++; - } - else - { - exclusionsPresent = enumer.MoveNext(); - } - curQubit++; - Debug.Assert(curQubit < NumQubits); - } - return numBorrowed; + return this.Borrow(numToBorrow, ConstructExcludedQubitsArray(curFrame)); } + #endregion + protected virtual void ReturnOneQubit(Qubit qubit) { + if (!DisableBorrowing) + { + bool success = curFrame.Locals.Remove(qubit); // Could be more efficient here going from the end manually. + Debug.Assert(success, "Returning qubit that is not a local variable in scope."); + } } /// @@ -519,7 +652,7 @@ protected virtual void ReturnOneQubit(Qubit qubit) /// public virtual bool ToBeReleasedAfterReturn(Qubit qubit) { - return BorrowingRefCountIsOne(qubit.Id); + return IsAllocatedForBorrowing(qubit.Id) && qubits[qubit.Id] == AllocatedForBorrowing; } /// diff --git a/src/Simulation/Common/QubitManagerTrackingScope.cs b/src/Simulation/Common/QubitManagerTrackingScope.cs deleted file mode 100644 index 5cd72c8fa05..00000000000 --- a/src/Simulation/Common/QubitManagerTrackingScope.cs +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Microsoft.Quantum.Simulation.Core; - -namespace Microsoft.Quantum.Simulation.Common -{ - public class QubitManagerTrackingScope : QubitManager, IQubitManager - { - - private class StackFrame - { - internal IApplyData Data; - internal IEnumerable QubitsInArgument => Data?.Qubits; - internal List _locals; // Qubits allocated/borrowed in the current operation - - public StackFrame() - { - Data = null; - } - - public StackFrame(IApplyData data) - { - Data = data; - } - - public List Locals - { - get - { - if (_locals == null) - { - _locals = new List(); - } - - return _locals; - } - } - } - - private readonly Stack operationStack; // Stack of operation calls. - private StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. - - public QubitManagerTrackingScope( - long qubitCapacity, - bool mayExtendCapacity = false, - bool disableBorrowing = false, - bool encourageReuse = true) - : base(qubitCapacity, mayExtendCapacity, disableBorrowing, encourageReuse) - { - if (!DisableBorrowing) - { - operationStack = new Stack(); - curFrame = new StackFrame(); - } - } - - public void OnOperationStart(ICallable operation, IApplyData values) - { - if (!DisableBorrowing) - { - operationStack.Push(curFrame); - curFrame = new StackFrame(values); - } - } - - public void OnOperationEnd(ICallable operation, IApplyData values) - { - if (!DisableBorrowing) - { - curFrame = operationStack.Pop(); - } - } - - protected override Qubit AllocateOneQubit(bool usedOnlyForBorrowing) - { - Qubit ret = base.AllocateOneQubit(usedOnlyForBorrowing); - if (!DisableBorrowing) - { - curFrame.Locals.Add(ret); - } - return ret; - } - - protected override void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) - { - base.ReleaseOneQubit(qubit, usedOnlyForBorrowing); - if (!DisableBorrowing) - { - bool success = curFrame.Locals.Remove(qubit); - Debug.Assert(success, "Releasing qubit that is not a local variable in scope."); - } - } - - protected override Qubit BorrowOneQubit(long id) - { - Qubit ret = base.BorrowOneQubit(id); - if (!DisableBorrowing) - { - curFrame.Locals.Add(ret); - } - return ret; - } - - protected override void ReturnOneQubit(Qubit qubit) - { - base.ReturnOneQubit(qubit); - if (!DisableBorrowing) - { - bool success = curFrame.Locals.Remove(qubit); // Could be more efficient here going from the end manually. - Debug.Assert(success, "Returning qubit that is not a local variable in scope."); - } - } - - private IEnumerable ExcludedQubitsForFrame(StackFrame curFrame) - { - var qubitsInArgument = curFrame.QubitsInArgument?.ToArray(); - long numExcluded = curFrame.Locals.Count + (qubitsInArgument?.Length ?? 0); - var excludedQubits = new Qubit[numExcluded]; - - int k = 0; - if (qubitsInArgument != null) - { - foreach (Qubit q in qubitsInArgument) - { - excludedQubits[k] = q; - k++; - } - } - foreach (Qubit q in curFrame.Locals) - { - excludedQubits[k] = q; - k++; - } - Debug.Assert(k == numExcluded); - - // The following is not really efficient, but let's wait to see if distinct can be part of the contract - // for the qubitsInArgument parameter of StartOperation call. - // Well, we are talking about really small arrays here anyway. - return excludedQubits.Where(q => q != null).Distinct().OrderBy(Qubit => Qubit.Id); - } - - private IEnumerable ConstructExcludedQubitsArray() - { - if (DisableBorrowing) - { - return Qubit.NO_QUBITS; - } - - return ExcludedQubitsForFrame(curFrame); - } - - private IEnumerable ConstructParentExcludedQubitsArray() - { - if (DisableBorrowing) - { - return Qubit.NO_QUBITS; - } - - if (operationStack.Count < 1) - { - return Qubit.NO_QUBITS; - } - - // curFrame is the current frame. operationStack only contains "out" frames, - // but not the current frame. Thus, the top of the stack is the parent frame, - // not the current frame. - return ExcludedQubitsForFrame(operationStack.Peek()); - } - - public virtual Qubit Borrow() - { - return base.Borrow(1, ConstructExcludedQubitsArray())[0]; - } - - public virtual IQArray Borrow(long numToBorrow) - { - return base.Borrow(numToBorrow, ConstructExcludedQubitsArray()); - } - - public override long GetQubitsAvailableToBorrowCount() - { - if (!DisableBorrowing) - { - return GetQubitsAvailableToBorrowCount(ConstructExcludedQubitsArray()); - } - else - { - return 0; - } - } - - public override long GetParentQubitsAvailableToBorrowCount() - { - if (!DisableBorrowing) - { - return GetQubitsAvailableToBorrowCount(ConstructParentExcludedQubitsArray()); - } - else - { - return 0; - } - } - } -} diff --git a/src/Simulation/Core/Qubit.cs b/src/Simulation/Core/Qubit.cs index 5681b0f5947..3132cee2a10 100644 --- a/src/Simulation/Core/Qubit.cs +++ b/src/Simulation/Core/Qubit.cs @@ -11,7 +11,7 @@ namespace Microsoft.Quantum.Simulation.Core /// /// Represents a Quantum Bit. /// - public class Qubit : IApplyData, IEquatable, IEqualityComparer + public abstract class Qubit : IApplyData, IEquatable, IEqualityComparer { [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static readonly Qubit[] NO_QUBITS = new Qubit[0]; diff --git a/src/Simulation/QCTraceSimulator/TraceableQubitManager.cs b/src/Simulation/QCTraceSimulator/TraceableQubitManager.cs index f11d9042056..14b0f5e02ef 100644 --- a/src/Simulation/QCTraceSimulator/TraceableQubitManager.cs +++ b/src/Simulation/QCTraceSimulator/TraceableQubitManager.cs @@ -12,7 +12,7 @@ namespace Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime /// Qubit manager for TraceableQubit type. Ensures that all the traceable /// qubits are configured as requested during qubit manage construction. /// - class TraceableQubitManager : QubitManagerTrackingScope + class TraceableQubitManager : QubitManager { const long NumQubits = 1024; diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs index 8ee972883a8..6913e068db5 100644 --- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs +++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs @@ -243,7 +243,7 @@ public void TestQubitManagerDiscouragingReuse() [Fact] public void TestQubitManagerTrackingScope() { - QubitManagerTrackingScope qm = new QubitManagerTrackingScope(20); + QubitManager qm = new QubitManager(20); Qubit q1 = qm.Allocate(); Assert.True(q1.Id == 0); @@ -302,7 +302,7 @@ public void TestQubitManagerTrackingScope() [Fact] public void TestQubitManagerDisabledBorrowing() { - QubitManagerTrackingScope qm = new QubitManagerTrackingScope(20, mayExtendCapacity: true, disableBorrowing: true); + QubitManager qm = new QubitManager(20, mayExtendCapacity: true, disableBorrowing: true); Qubit q1 = qm.Allocate(); Assert.True(q1.Id == 0); @@ -377,7 +377,7 @@ public void TestQubitManagerDisabledBorrowing() [Fact] public void TestQubitManagerGrowth() { - QubitManagerTrackingScope qm = new QubitManagerTrackingScope(7, mayExtendCapacity : true, disableBorrowing: false); + QubitManager qm = new QubitManager(7, mayExtendCapacity : true, disableBorrowing: false); Qubit q1 = qm.Allocate(); Assert.True(q1.Id == 0); diff --git a/src/Simulation/Simulators.Tests/TrivialSimulator.cs b/src/Simulation/Simulators.Tests/TrivialSimulator.cs index f11afdea853..7b10bf834db 100644 --- a/src/Simulation/Simulators.Tests/TrivialSimulator.cs +++ b/src/Simulation/Simulators.Tests/TrivialSimulator.cs @@ -11,7 +11,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests /// public class TrivialSimulator : SimulatorBase { - public TrivialSimulator() : base(new QubitManagerTrackingScope(32)) + public TrivialSimulator() : base(new QubitManager(32)) { } diff --git a/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs index c941ec7e133..ca4235c4fbf 100644 --- a/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs +++ b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs @@ -32,7 +32,7 @@ public IQuantumProcessor QuantumProcessor /// A seed to be used by Q# Microsoft.Quantum.Intrinsic.Random operation. public QuantumProcessorDispatcher(IQuantumProcessor? quantumProcessor = null, IQubitManager? qubitManager = null, int? randomSeed = null) : base( - qubitManager ?? new QubitManagerTrackingScope( + qubitManager ?? new QubitManager( PreallocatedQubitCount, mayExtendCapacity: true, disableBorrowing: false ), diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs index 2c60924ae16..76e31e9204f 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs @@ -11,7 +11,7 @@ namespace Microsoft.Quantum.Simulation.Simulators { public partial class QuantumSimulator { - class QSimQubitManager : QubitManagerTrackingScope + class QSimQubitManager : QubitManager { readonly bool throwOnReleasingQubitsNotInZeroState; diff --git a/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs b/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs index 81dae1c4aa5..3b2fb99be5d 100644 --- a/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs +++ b/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs @@ -46,7 +46,7 @@ public ToffoliSimulator() : this(DEFAULT_QUBIT_COUNT) { } /// There is an overhead of one byte of memory usage per allocated qubit. /// There is no time overhead from allocating more qubits. public ToffoliSimulator(uint qubitCount) - : base(new QubitManagerTrackingScope(qubitCapacity: qubitCount, mayExtendCapacity: false, disableBorrowing: false)) + : base(new QubitManager(qubitCapacity: qubitCount, mayExtendCapacity: false, disableBorrowing: false)) { this.State = new bool[qubitCount]; this.borrowedQubitStates = new Dictionary>(); From 6d358be0ad98a7ee26fb3fba4c9225ee0a2b5354 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 2 Sep 2020 20:07:58 -0700 Subject: [PATCH 04/20] committing a working version --- src/Simulation/Common/AssemblyInfo.cs | 7 ++ src/Simulation/Common/QubitManager.cs | 82 ++++++++++--------- .../Core/Properties/AssemblyInfo.cs | 2 - src/Simulation/Core/Qubit.cs | 2 +- .../Simulators/QuantumSimulator/Qubit.cs | 2 - 5 files changed, 50 insertions(+), 45 deletions(-) create mode 100644 src/Simulation/Common/AssemblyInfo.cs diff --git a/src/Simulation/Common/AssemblyInfo.cs b/src/Simulation/Common/AssemblyInfo.cs new file mode 100644 index 00000000000..f9807358194 --- /dev/null +++ b/src/Simulation/Common/AssemblyInfo.cs @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Runtime.CompilerServices; + +// Allow the test assembly to use our internal methods +[assembly: InternalsVisibleTo("Tests.Microsoft.Quantum.Simulators" + SigningConstants.PUBLIC_KEY)] diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 5eeb7de4875..e849f5348f2 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -213,21 +213,14 @@ public bool IsValid(Qubit qubit) return true; } - public bool IsFree(Qubit qubit) - { - if (!IsValid(qubit)) { return false; } - return IsFree(qubit.Id); - } - private bool IsFree(long id) { return qubits[id] < Allocated; } - public bool IsDisabled(Qubit qubit) + public bool IsFree(Qubit qubit) { - if (!IsValid(qubit)) { return false; } - return IsDisabled(qubit.Id); + return IsValid(qubit) && IsFree(qubit.Id); } private bool IsDisabled(long id) @@ -235,34 +228,23 @@ private bool IsDisabled(long id) return (qubits[id] == Disabled); } - private bool IsAllocatedForBorrowing(long id) + public bool IsDisabled(Qubit qubit) { - return qubits[id] >= AllocatedForBorrowing; + return IsValid(qubit) && IsDisabled(qubit.Id); } - // Returns true if qubit needs to be released: It has been allocated for borrowing and is not borrowed any more. - private bool DecreaseBorrowingRefCount(long id) + private bool IsAllocatedForBorrowing(long id) { - if (IsAllocatedForBorrowing(id)) { - if (qubits[id] == AllocatedForBorrowing) - { - return true; - } - else - { - qubits[id]--; - return false; - } - } else - { - return false; - } + return qubits[id] >= AllocatedForBorrowing; } + #region Allocate + /// /// Allocates a qubit. + /// Returns null if the qubit cannot be allocated. /// - protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing) + protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing = false) { if (free == None) { @@ -332,10 +314,11 @@ protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing) /// /// Allocates a qubit. + /// Throws a NotEnoughQubits exception if the qubit cannot be allocated. /// - public virtual Qubit Allocate() + public Qubit Allocate() { - Qubit qb = AllocateOneQubit(usedOnlyForBorrowing: false); + Qubit qb = AllocateOneQubit(); if (qb == null) { throw new NotEnoughQubits(1, GetFreeQubitsCount()); @@ -345,8 +328,9 @@ public virtual Qubit Allocate() /// /// Allocates numToAllocate new qubits. + /// Throws a NotEnoughQubits exception without allocating any qubits if the qubits cannot be allocated. /// - public virtual IQArray Allocate(long numToAllocate) + public IQArray Allocate(long numToAllocate) { if (numToAllocate < 0) { @@ -358,10 +342,9 @@ public virtual IQArray Allocate(long numToAllocate) } QArray result = QArray.Create(numToAllocate); - for (int i = 0; i < numToAllocate; i++) { - result.Modify(i, AllocateOneQubit(usedOnlyForBorrowing: false)); + result.Modify(i, AllocateOneQubit()); if (result[i] == null) { for (int k = 0; k < i; k++) @@ -375,7 +358,11 @@ public virtual IQArray Allocate(long numToAllocate) return result; } - protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) + #endregion + + #region Release + + protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing = false) { if (qubits[qubit.Id] == Disabled) { @@ -427,15 +414,15 @@ protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) /// /// Releases a given qubit. /// - public virtual void Release(Qubit qubit) + public void Release(Qubit qubit) { - ReleaseOneQubit(qubit, usedOnlyForBorrowing: false); + ReleaseOneQubit(qubit); } /// /// Releases a set of given qubits. /// - public virtual void Release(IQArray qubitsToRelease) + public void Release(IQArray qubitsToRelease) { if (qubitsToRelease == null || qubitsToRelease.Length == 0) { @@ -444,10 +431,12 @@ public virtual void Release(IQArray qubitsToRelease) for (long i = qubitsToRelease.Length-1; i>=0; i--) { // Going from the end is more efficient in case we are tracking scope. - this.ReleaseOneQubit(qubitsToRelease[i], usedOnlyForBorrowing: false); + this.ReleaseOneQubit(qubitsToRelease[i]); } } + #endregion + protected virtual void DisableOneQubit(Qubit qubit) { // Note: Borrowed qubits cannot be disabled. @@ -685,11 +674,24 @@ public virtual void Return(Qubit qubit) { if (DisableBorrowing) { - this.ReleaseOneQubit(qubit, usedOnlyForBorrowing: false); + this.ReleaseOneQubit(qubit); } else { - if (DecreaseBorrowingRefCount(qubit.Id)) + var needsToBeReleased = false; + if (IsAllocatedForBorrowing(qubit.Id)) + { + if (qubits[qubit.Id] == AllocatedForBorrowing) + { + needsToBeReleased = true; + } + else + { + qubits[qubit.Id]--; + } + } + + if (needsToBeReleased) { this.ReleaseOneQubit(qubit, usedOnlyForBorrowing: true); } diff --git a/src/Simulation/Core/Properties/AssemblyInfo.cs b/src/Simulation/Core/Properties/AssemblyInfo.cs index c2a5d12dced..f9807358194 100644 --- a/src/Simulation/Core/Properties/AssemblyInfo.cs +++ b/src/Simulation/Core/Properties/AssemblyInfo.cs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; // Allow the test assembly to use our internal methods [assembly: InternalsVisibleTo("Tests.Microsoft.Quantum.Simulators" + SigningConstants.PUBLIC_KEY)] diff --git a/src/Simulation/Core/Qubit.cs b/src/Simulation/Core/Qubit.cs index 3132cee2a10..3ed1d618dec 100644 --- a/src/Simulation/Core/Qubit.cs +++ b/src/Simulation/Core/Qubit.cs @@ -14,7 +14,7 @@ namespace Microsoft.Quantum.Simulation.Core public abstract class Qubit : IApplyData, IEquatable, IEqualityComparer { [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public static readonly Qubit[] NO_QUBITS = new Qubit[0]; + public static readonly Qubit[] NO_QUBITS = Array.Empty(); /// /// Used by UDTs that extend Qubit. diff --git a/src/Simulation/Simulators/QuantumSimulator/Qubit.cs b/src/Simulation/Simulators/QuantumSimulator/Qubit.cs index 9fd546bf6b5..4a9f98c8760 100644 --- a/src/Simulation/Simulators/QuantumSimulator/Qubit.cs +++ b/src/Simulation/Simulators/QuantumSimulator/Qubit.cs @@ -4,10 +4,8 @@ using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; using System; -using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Text; namespace Microsoft.Quantum.Simulation.Simulators { From ff3297ab1feb4d0938464daddb71004197559017 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 05:44:01 -0700 Subject: [PATCH 05/20] some bug --- src/Simulation/Common/IQubitManager.cs | 3 +- src/Simulation/Common/QubitManager.cs | 294 ++++++++---------- src/Simulation/Common/SimulatorBase.cs | 3 +- src/Simulation/QsharpCore/Environment.qs | 5 +- .../Simulators.Tests/QubitManagerTests.cs | 19 +- 5 files changed, 146 insertions(+), 178 deletions(-) diff --git a/src/Simulation/Common/IQubitManager.cs b/src/Simulation/Common/IQubitManager.cs index 774158b80ab..0c8cd255f42 100644 --- a/src/Simulation/Common/IQubitManager.cs +++ b/src/Simulation/Common/IQubitManager.cs @@ -3,8 +3,8 @@ namespace Microsoft.Quantum.Simulation.Common { - using Microsoft.Quantum.Simulation.Core; using System.Collections.Generic; + using Microsoft.Quantum.Simulation.Core; public interface IQubitManager { @@ -32,7 +32,6 @@ public interface IQubitManager long GetFreeQubitsCount(); long GetQubitsAvailableToBorrowCount(); - long GetParentQubitsAvailableToBorrowCount(); // Required for GetAvailableQubitsToBorrow long GetAllocatedQubitsCount(); IEnumerable GetAllocatedIds(); diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index e849f5348f2..7a8e3db0994 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -18,16 +18,26 @@ namespace Microsoft.Quantum.Simulation.Common /// public class QubitManager : IQubitManager { - long NumQubits; // Total number of qubits this QubitManager is capable of handling. - long None; // Indicates the end of the list of free qubits. If we reach it - we are out of qubits. - long Allocated; // All qubits allocated by user will be marked with this number. - long Disabled; // All qubits disabled via DisableQubit interface will be marked with this number. - long AllocatedForBorrowing; // All qubits allocated only for borrowing, will be marked with this number or higher. - long[] qubits; // Tracks the allocation state of all qubits. - long free; // Points to the first free (unallocated) qubit. - long freeTail; // Points to the last free (unallocated) qubit. Only valid iff (!EncourageReuse). - long numAllocatedQubits; // Tracking this for optimization. - long numDisabledQubits; // Number of disabled qubits. + /// + /// Total number of qubits this QubitManager is capable of handling. + /// + protected long NumQubits; + /// + /// The number of currently allocated qubits. + /// + protected long NumAllocatedQubits; + /// + /// The number of disabled qubits. + /// + protected long NumDisabledQubits; + + protected long[] qubits; // Tracks the allocation state of all qubits. + private long None; // Indicates the end of the list of free qubits. If we reach it - we are out of qubits. + private long Allocated; // All qubits allocated by user will be marked with this number. + private long Disabled; // All qubits disabled via DisableQubit interface will be marked with this number. + private long AllocatedForBorrowing; // All qubits allocated only for borrowing, will be marked with this number or higher. + private long free; // Points to the first free (unallocated) qubit. + private long freeTail; // Points to the last free (unallocated) qubit. Only valid iff (!EncourageReuse). // Options readonly bool MayExtendCapacity; @@ -48,10 +58,21 @@ public class QubitManager : IQubitManager // For qubits that are free, the array stores the index of the next free qubit (a value less than "Allocated" constant). // The last free qubit in the list of free qubits stores the value "None". + private void UpdateQubitCapacity(long newQubitCapacity) + { + Debug.Assert(newQubitCapacity < MaxQubitCapacity); + NumQubits = newQubitCapacity; + None = NumQubits; + Allocated = NumQubits + 1; + Disabled = NumQubits + 2; + AllocatedForBorrowing = NumQubits + 3; + this.qubits = new long[NumQubits]; + } + // stack frame management needed to support borrowing qubits #region StackFrameManagement - private class StackFrame + protected class StackFrame { internal IApplyData Data; internal IEnumerable QubitsInArgument => Data?.Qubits; @@ -81,10 +102,10 @@ public List Locals } } - private readonly Stack operationStack; // Stack of operation calls. - private StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. + protected readonly Stack operationStack; // Stack of operation calls. + protected StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. - public void OnOperationStart(ICallable _, IApplyData values) + public virtual void OnOperationStart(ICallable _, IApplyData values) { if (!DisableBorrowing) { @@ -93,7 +114,7 @@ public void OnOperationStart(ICallable _, IApplyData values) } } - public void OnOperationEnd(ICallable _, IApplyData values) + public virtual void OnOperationEnd(ICallable _, IApplyData values) { if (!DisableBorrowing) { @@ -161,8 +182,8 @@ public QubitManager( free = 0; freeTail = NumQubits - 1; - numAllocatedQubits = 0; - numDisabledQubits = 0; + NumAllocatedQubits = 0; + NumDisabledQubits = 0; if (!DisableBorrowing) { @@ -194,18 +215,7 @@ public virtual Qubit CreateQubitObject(long id) return new QubitNonAbstract((int)id); } - private void UpdateQubitCapacity(long newQubitCapacity) - { - Debug.Assert(newQubitCapacity < MaxQubitCapacity); - NumQubits = newQubitCapacity; - None = NumQubits; - Allocated = NumQubits + 1; - Disabled = NumQubits + 2; - AllocatedForBorrowing = NumQubits + 3; - this.qubits = new long[NumQubits]; - } - - public bool IsValid(Qubit qubit) + public virtual bool IsValid(Qubit qubit) { if (qubit == null) { return false; } if (qubit.Id >= NumQubits) { return false; } @@ -218,7 +228,7 @@ private bool IsFree(long id) return qubits[id] < Allocated; } - public bool IsFree(Qubit qubit) + public virtual bool IsFree(Qubit qubit) { return IsValid(qubit) && IsFree(qubit.Id); } @@ -228,7 +238,7 @@ private bool IsDisabled(long id) return (qubits[id] == Disabled); } - public bool IsDisabled(Qubit qubit) + public virtual bool IsDisabled(Qubit qubit) { return IsValid(qubit) && IsDisabled(qubit.Id); } @@ -238,6 +248,68 @@ private bool IsAllocatedForBorrowing(long id) return qubits[id] >= AllocatedForBorrowing; } + public virtual long GetQubitsAvailableToBorrowCount() + { + return DisableBorrowing ? 0 : NumAllocatedQubits - ConstructExcludedQubitsArray(curFrame).Count(); + } + + public long GetFreeQubitsCount() + { + return NumQubits - NumDisabledQubits - NumAllocatedQubits; + } + + public long GetAllocatedQubitsCount() + { + return NumAllocatedQubits; + } + + public virtual IEnumerable GetAllocatedIds() + { + for (long i = 0; i < qubits.LongLength; i++) + { + if (!IsFree(i)) yield return i; + } + } + + #region Disable + + protected virtual void DisableOneQubit(Qubit qubit) + { + qubits[qubit.Id] = Disabled; + NumDisabledQubits++; + + NumAllocatedQubits--; + Debug.Assert(NumAllocatedQubits >= 0); + } + + /// + /// Disables a given qubit. + /// Once a qubit is disabled it can never be reallocated. + /// + public void Disable(Qubit qubit) + { + DisableOneQubit(qubit); + } + + /// + /// Disables a set of given qubits. + /// Once a qubit is disabled it can never be reallocated. + /// + public void Disable(IQArray qubitsToDisable) + { + if (qubitsToDisable == null || qubitsToDisable.Length == 0) + { + return; + } + + foreach (Qubit qubit in qubitsToDisable) + { + this.DisableOneQubit(qubit); + } + } + + #endregion + #region Allocate /// @@ -304,7 +376,7 @@ protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing = false) free = qubits[free]; qubits[temp] = (usedOnlyForBorrowing ? AllocatedForBorrowing : Allocated); - numAllocatedQubits++; + NumAllocatedQubits++; if (!DisableBorrowing) { curFrame.Locals.Add(ret); @@ -400,8 +472,8 @@ protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing = freeTail = qubit.Id; } - numAllocatedQubits--; - Debug.Assert(numAllocatedQubits >= 0); + NumAllocatedQubits--; + Debug.Assert(NumAllocatedQubits >= 0); } if (!DisableBorrowing) @@ -437,85 +509,6 @@ public void Release(IQArray qubitsToRelease) #endregion - protected virtual void DisableOneQubit(Qubit qubit) - { - // Note: Borrowed qubits cannot be disabled. - Debug.Assert(qubits[qubit.Id] == Allocated); - qubits[qubit.Id] = Disabled; - numDisabledQubits++; - - numAllocatedQubits--; - Debug.Assert(numAllocatedQubits >= 0); - } - - /// - /// Disables a given qubit. - /// Once a qubit is disabled it can never be reallocated. - /// - public virtual void Disable(Qubit qubit) - { - DisableOneQubit(qubit); - } - - /// - /// Disables a set of given qubits. - /// Once a qubit is disabled it can never be reallocated. - /// - public virtual void Disable(IQArray qubitsToDisable) - { - if (qubitsToDisable == null || qubitsToDisable.Length == 0) - { - return; - } - - foreach (Qubit qubit in qubitsToDisable) - { - this.DisableOneQubit(qubit); - } - } - - - public long GetQubitsAvailableToBorrowCount(IEnumerable excludedQubits) - { - // Note: this function is not allowed to call its no-parameters cousin: GetQubitsAvailableToBorrowCount() - return numAllocatedQubits - excludedQubits.Count(); - } - - public virtual long GetQubitsAvailableToBorrowCount() - { - return DisableBorrowing - ? 0 - : GetQubitsAvailableToBorrowCount(ConstructExcludedQubitsArray(curFrame)); - } - - public virtual long GetParentQubitsAvailableToBorrowCount() - { - // The operationStack only contains "out" frames, but not the current frame. - // Thus, the top of the stack is the parent frame, not the current frame. - var parentFrame = operationStack.TryPeek(out StackFrame frame) ? frame : null; - return DisableBorrowing - ? 0 - : GetQubitsAvailableToBorrowCount(ConstructExcludedQubitsArray(parentFrame)); - } - - public long GetFreeQubitsCount() - { - return NumQubits - numDisabledQubits - numAllocatedQubits; - } - - public long GetAllocatedQubitsCount() - { - return numAllocatedQubits; - } - - public IEnumerable GetAllocatedIds() - { - for (long i = 0; i < qubits.LongLength; i++) - { - if (!IsFree(i)) yield return i; - } - } - #region Borrow protected virtual Qubit BorrowOneQubit(long id) @@ -533,11 +526,11 @@ protected virtual Qubit BorrowOneQubit(long id) return ret; } - private long TryBorrow(long numToBorrow, QArray result, IEnumerable excludedQubitsSortedById) + internal long TryBorrow(QArray borrowed, IEnumerable excludedQubitsSortedById) { long curQubit = 0; long curBorrowed = 0; - long numBorrowed = System.Math.Min(GetQubitsAvailableToBorrowCount(excludedQubitsSortedById), numToBorrow); + long numBorrowed = System.Math.Min(NumAllocatedQubits - excludedQubitsSortedById.Count(), borrowed.Length); IEnumerator enumer = excludedQubitsSortedById.GetEnumerator(); bool exclusionsPresent = enumer.MoveNext(); @@ -552,7 +545,7 @@ private long TryBorrow(long numToBorrow, QArray result, IEnumerable= curQubit)); if ((!exclusionsPresent) || (enumer.Current.Id != curQubit)) { - result.Modify(curBorrowed, BorrowOneQubit(curQubit)); + borrowed.Modify(curBorrowed, BorrowOneQubit(curQubit)); curBorrowed++; } else @@ -562,17 +555,31 @@ private long TryBorrow(long numToBorrow, QArray result, IEnumerable /// Borrows a number of qubits. Chooses them from among already allocated ones. - /// Makes sure borrowed qubits are not on the exclusion list. - /// Exclusion list is supposed to contain qubits that can not be borrowed, - /// for example those, that are being used (or could be used) in the current context. /// If there are not enough qubits to borrow, allocates new ones. /// - public virtual IQArray Borrow(long numToBorrow, IEnumerable excludedQubitsSortedById) // Note, excluded could be an array of Ids for efficiency, if it is convenient for compiler. + public virtual IQArray Borrow(long numToBorrow) { if (numToBorrow < 0) { @@ -588,40 +595,14 @@ private long TryBorrow(long numToBorrow, QArray result, IEnumerable result = QArray.Create(numToBorrow); - long numBorrowed = TryBorrow(numToBorrow, result, excludedQubitsSortedById); - - if (numBorrowed < numToBorrow) - { // Not enough qubits to borrow. Allocate what was not borrowed. - for (long i = numBorrowed; i < numToBorrow; i++) - { - result.Modify(i, AllocateOneQubit(usedOnlyForBorrowing: true)); - if (result[(int)i] == null) - { - for (long k = numBorrowed; k < i; k++) - { - ReleaseOneQubit(result[(int)k], usedOnlyForBorrowing: true); - } - throw new NotEnoughQubits(numToBorrow, numBorrowed + GetFreeQubitsCount()); - } - } - } - + _ = TryBorrow(result, ConstructExcludedQubitsArray(curFrame)); return result; } public Qubit Borrow() { - return this.Borrow(1, ConstructExcludedQubitsArray(curFrame))[0]; - } - - public IQArray Borrow(long numToBorrow) - { - return this.Borrow(numToBorrow, ConstructExcludedQubitsArray(curFrame)); + return this.Borrow(1)[0]; } #endregion @@ -706,7 +687,7 @@ public virtual void Return(Qubit qubit) /// Returns a set of borrowed qubits given. /// Releases those that have been allocated just for borrowing. /// - public virtual void Return(IQArray qubitsToReturn) + public void Return(IQArray qubitsToReturn) { if (qubitsToReturn == null || qubitsToReturn.Length == 0) { @@ -718,21 +699,6 @@ public virtual void Return(IQArray qubitsToReturn) this.Return(qubitsToReturn[i]); } } - - /// - /// Same as Borrow, but allows array of exluded qubits to be unsorted. It is recommended to use Borrow instead. - /// - /// - /// - /// - public virtual IQArray BorrowUnsorted(long numToBorrow, IEnumerable excludedQubits) // Note, excluded could be an array of Ids for efficiency, if it is convenient for compiler. - { - if (DisableBorrowing) - { - return Allocate(numToBorrow); - } - return Borrow(numToBorrow, excludedQubits.OrderBy(Qubit => Qubit.Id)); - } } } diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index 8f5f2e3182f..c38fc99d7d4 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -429,8 +429,7 @@ public GetQubitsAvailableToBorrow(SimulatorBase m) : base(m) sim = m; } - public override Func __Body__ => (arg) => sim.QubitManager.GetParentQubitsAvailableToBorrowCount() + - sim.QubitManager.GetFreeQubitsCount(); + public override Func __Body__ => (arg) => sim.QubitManager.GetQubitsAvailableToBorrowCount(); } /// diff --git a/src/Simulation/QsharpCore/Environment.qs b/src/Simulation/QsharpCore/Environment.qs index 7cc91153d50..145a9f0d645 100644 --- a/src/Simulation/QsharpCore/Environment.qs +++ b/src/Simulation/QsharpCore/Environment.qs @@ -20,11 +20,10 @@ namespace Microsoft.Quantum.Environment { /// # Summary /// Returns the number of qubits currently available to borrow. - /// This includes unused qubits; that is, this includes the qubits - /// returned by `GetQubitsAvailableToUse`. /// /// # Output - /// The number of qubits that could be allocated in a `borrowing` statement. + /// The number of qubits that could be borrowed and + /// won't be allocated as part of a `borrowing` statement. /// If the target machine being used does not provide this information, then /// `-1` is returned. /// diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs index 6913e068db5..f7bfb4a6b90 100644 --- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs +++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs @@ -64,7 +64,9 @@ public void TestQubitManager() long qubitsAvailable; qubitsAvailable = qm.GetFreeQubitsCount(); - IQArray qab = qm.Borrow(5, exclusion); + QArray qab = QArray.Create(5); + long nrBorrowed = qm.TryBorrow(qab, exclusion); + Assert.Equal(4, nrBorrowed); Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); Assert.True(qab[0].Id == 0); Assert.True(qab[1].Id == 2); @@ -77,7 +79,9 @@ public void TestQubitManager() // Test borrowing of the same qubit again qubitsAvailable = qm.GetFreeQubitsCount(); - IQArray qb1 = qm.Borrow(1, exclusion); + QArray qb1 = QArray.Create(1); + nrBorrowed = qm.TryBorrow(qb1, exclusion); + Assert.Equal(1, nrBorrowed); Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 0); Assert.True(qb1[0].Id == 0); qm.Return(qb1[0]); @@ -92,7 +96,7 @@ public void TestQubitManager() qm.Release(q4); qm.Release(qa1[2]); qm.Release(q1); - + IQArray qa3 = qm.Allocate(4); Assert.True(qa3.Length == 4); Assert.True(qa3[0].Id == 0); @@ -104,7 +108,7 @@ public void TestQubitManager() Qubit q8 = qm.Allocate(); Assert.True(q8.Id == 11); qm.Disable(q8); - IQArray qab2 = qm.Borrow(12, null); + IQArray qab2 = qm.Borrow(12); Assert.True(qab2[11].Id == 12); // make sure 11 is not borrowed. qm.Release(q8); qm.Return(qab2); @@ -119,7 +123,8 @@ public void TestQubitManager() IQArray n_q; n_q = qm.Allocate(0); Assert.True(n_q.Length == 0); - n_q = qm.Borrow(0, exclusion); + nrBorrowed = qm.TryBorrow(new QArray(), exclusion); + Assert.Equal(0, nrBorrowed); Assert.True(n_q.Length == 0); } @@ -136,7 +141,7 @@ public void TestQubitManager() { QubitManager qm_small = new QubitManager(2); IQArray n_q; - Assert.Throws(() => n_q = qm_small.Borrow(5, null)); + Assert.Throws(() => n_q = qm_small.Borrow(5)); } // Test for negative input to allocate and borrow. @@ -148,7 +153,7 @@ public void TestQubitManager() { QubitManager qm_small = new QubitManager(20); IQArray n_q; - Assert.Throws(() => n_q = qm_small.Borrow(-2, null)); + Assert.Throws(() => n_q = qm_small.Borrow(-2)); } } From 45c9a56cba2ac7612b63d72c4f152df883aa9ca2 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 06:49:47 -0700 Subject: [PATCH 06/20] found and fixed the bug (which was in the original code) --- src/Simulation/Common/QubitManager.cs | 7 ++++--- src/Simulation/Simulators.Tests/QubitManagerTests.cs | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 7a8e3db0994..ef144c2c924 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -129,8 +129,9 @@ private IEnumerable ConstructExcludedQubitsArray(StackFrame frame) return Qubit.NO_QUBITS; } - var qubitsInArgument = frame.QubitsInArgument?.ToArray(); - long numExcluded = frame.Locals.Count + (qubitsInArgument?.Length ?? 0); + var qubitsInArgument = frame.QubitsInArgument?.Where(q => !this.IsDisabled(q)).ToArray(); + var localQubits = frame.Locals.Where(q => !this.IsDisabled(q)); + long numExcluded = localQubits.Count() + (qubitsInArgument?.Length ?? 0); var excludedQubits = new Qubit[numExcluded]; int k = 0; @@ -142,7 +143,7 @@ private IEnumerable ConstructExcludedQubitsArray(StackFrame frame) k++; } } - foreach (Qubit q in frame.Locals) + foreach (Qubit q in localQubits) { excludedQubits[k] = q; k++; diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs index f7bfb4a6b90..84e8c3d4191 100644 --- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs +++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs @@ -17,7 +17,7 @@ public class QubitManagerTests [Fact] public void TestQubitManager() { - QubitManager qm = new QubitManager(20); + QubitManager qm = new QubitManager(30); // Test allocation of single qubit Qubit q1 = qm.Allocate(); @@ -109,16 +109,16 @@ public void TestQubitManager() Assert.True(q8.Id == 11); qm.Disable(q8); IQArray qab2 = qm.Borrow(12); - Assert.True(qab2[11].Id == 12); // make sure 11 is not borrowed. + Assert.True(qab2[11].Id == 23); // make sure 11 is not borrowed. qm.Release(q8); qm.Return(qab2); - + IQArray qa4 = qm.Allocate(2); Assert.True(qa4[0].Id == 12); // make sure 11 is not reused. Assert.True(qa4[1].Id == 13); // make sure 11 is not reused. qm.Release(qa4); - + { // Test allocating zero qubits IQArray n_q; n_q = qm.Allocate(0); From 2cc703762fc15c6630b1a9c0c025b5af7f0975d6 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 17:43:05 -0700 Subject: [PATCH 07/20] cleaned up the structure --- src/Simulation/Common/QubitManager.cs | 295 +++++++++--------- .../Simulators.Tests/QubitManagerTests.cs | 13 +- .../QuantumSimulator/QubitManager.cs | 8 +- 3 files changed, 149 insertions(+), 167 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index ef144c2c924..b2fddcc256d 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -30,8 +30,11 @@ public class QubitManager : IQubitManager /// The number of disabled qubits. /// protected long NumDisabledQubits; + /// + /// Tracks the allocation state of all qubits. + /// + protected long[] qubits; - protected long[] qubits; // Tracks the allocation state of all qubits. private long None; // Indicates the end of the list of free qubits. If we reach it - we are out of qubits. private long Allocated; // All qubits allocated by user will be marked with this number. private long Disabled; // All qubits disabled via DisableQubit interface will be marked with this number. @@ -40,8 +43,8 @@ public class QubitManager : IQubitManager private long freeTail; // Points to the last free (unallocated) qubit. Only valid iff (!EncourageReuse). // Options - readonly bool MayExtendCapacity; - readonly bool EncourageReuse; + protected readonly bool MayExtendCapacity; + protected readonly bool EncourageReuse; public bool DisableBorrowing { get; } const long MaxQubitCapacity = long.MaxValue - 3; @@ -122,38 +125,23 @@ public virtual void OnOperationEnd(ICallable _, IApplyData values) } } - private IEnumerable ConstructExcludedQubitsArray(StackFrame frame) + protected IEnumerable QubitsInUse(StackFrame frame) { if (DisableBorrowing || frame == null) { return Qubit.NO_QUBITS; } - var qubitsInArgument = frame.QubitsInArgument?.Where(q => !this.IsDisabled(q)).ToArray(); - var localQubits = frame.Locals.Where(q => !this.IsDisabled(q)); - long numExcluded = localQubits.Count() + (qubitsInArgument?.Length ?? 0); - var excludedQubits = new Qubit[numExcluded]; - - int k = 0; - if (qubitsInArgument != null) - { - foreach (Qubit q in qubitsInArgument) - { - excludedQubits[k] = q; - k++; - } - } - foreach (Qubit q in localQubits) - { - excludedQubits[k] = q; - k++; - } - Debug.Assert(k == numExcluded); + return frame.Locals.Concat(frame.QubitsInArgument ?? Array.Empty()) + .Where(q => q != null && !this.IsDisabled(q)); + } + protected int QubitsInUseCount(StackFrame frame) + { // The following is not really efficient, but let's wait to see if distinct can be part of the contract // for the qubitsInArgument parameter of StartOperation call. // Well, we are talking about really small arrays here anyway. - return excludedQubits.Where(q => q != null).Distinct().OrderBy(Qubit => Qubit.Id); + return QubitsInUse(frame).Distinct().Count(); } #endregion @@ -251,7 +239,7 @@ private bool IsAllocatedForBorrowing(long id) public virtual long GetQubitsAvailableToBorrowCount() { - return DisableBorrowing ? 0 : NumAllocatedQubits - ConstructExcludedQubitsArray(curFrame).Count(); + return DisableBorrowing ? 0 : NumAllocatedQubits - QubitsInUseCount(curFrame); } public long GetFreeQubitsCount() @@ -272,24 +260,50 @@ public virtual IEnumerable GetAllocatedIds() } } - #region Disable + /// + /// Returns true if a qubit has been allocated just for borrowing, has been borrowed exactly once, + /// and thus will be released after it is returned. + /// + public virtual bool ToBeReleasedAfterReturn(Qubit qubit) + { + return IsAllocatedForBorrowing(qubit.Id) && qubits[qubit.Id] == AllocatedForBorrowing; + } - protected virtual void DisableOneQubit(Qubit qubit) + /// + /// Returns a count of input qubits that have been allocated just for borrowing, borrowed exactly once, + /// and thus will be released after they are returned. + /// + public virtual long ToBeReleasedAfterReturnCount(IQArray qubitsToReturn) { - qubits[qubit.Id] = Disabled; - NumDisabledQubits++; + if (qubitsToReturn == null || qubitsToReturn.Length == 0) + { + return 0; + } - NumAllocatedQubits--; - Debug.Assert(NumAllocatedQubits >= 0); + long count = 0; + foreach (Qubit qubit in qubitsToReturn) + { + if (this.ToBeReleasedAfterReturn(qubit)) + { + count++; + } + } + return count; } + #region Disable + /// /// Disables a given qubit. /// Once a qubit is disabled it can never be reallocated. /// - public void Disable(Qubit qubit) + public virtual void Disable(Qubit qubit) { - DisableOneQubit(qubit); + qubits[qubit.Id] = Disabled; + NumDisabledQubits++; + + NumAllocatedQubits--; + Debug.Assert(NumAllocatedQubits >= 0); } /// @@ -305,7 +319,7 @@ public void Disable(IQArray qubitsToDisable) foreach (Qubit qubit in qubitsToDisable) { - this.DisableOneQubit(qubit); + this.Disable(qubit); } } @@ -317,7 +331,7 @@ public void Disable(IQArray qubitsToDisable) /// Allocates a qubit. /// Returns null if the qubit cannot be allocated. /// - protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing = false) + protected virtual Qubit Allocate(bool usedOnlyForBorrowing) { if (free == None) { @@ -391,7 +405,7 @@ protected virtual Qubit AllocateOneQubit(bool usedOnlyForBorrowing = false) /// public Qubit Allocate() { - Qubit qb = AllocateOneQubit(); + Qubit qb = Allocate(usedOnlyForBorrowing: false); if (qb == null) { throw new NotEnoughQubits(1, GetFreeQubitsCount()); @@ -417,12 +431,12 @@ public IQArray Allocate(long numToAllocate) QArray result = QArray.Create(numToAllocate); for (int i = 0; i < numToAllocate; i++) { - result.Modify(i, AllocateOneQubit()); + result.Modify(i, Allocate(usedOnlyForBorrowing: false)); if (result[i] == null) { for (int k = 0; k < i; k++) { - Release(result[k]); + Release(result[k], wasUsedOnlyForBorrowing: false); } throw new NotEnoughQubits(numToAllocate, GetFreeQubitsCount()); } @@ -435,48 +449,46 @@ public IQArray Allocate(long numToAllocate) #region Release - protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing = false) + protected virtual void Release(Qubit qubit, bool wasUsedOnlyForBorrowing) { if (qubits[qubit.Id] == Disabled) { // Nothing to do. It will stay disabled. - // Alternatively, we could mark is as None here. + return; } + + if (qubits[qubit.Id] != (wasUsedOnlyForBorrowing ? AllocatedForBorrowing : Allocated)) + { + throw new ArgumentException("Attempt to free qubit that has not been allocated."); + } + + if (EncourageReuse) { + qubits[qubit.Id] = free; + free = qubit.Id; + } else { - long Occupied = (usedOnlyForBorrowing ? AllocatedForBorrowing : Allocated); - if (qubits[qubit.Id] != Occupied) - { - throw new ArgumentException("Attempt to free qubit that has not been allocated."); - } - if (EncourageReuse) { - qubits[qubit.Id] = free; - free = qubit.Id; - } - else + // If we are allowed to extend capacity we will never reuse this qubit, + // otherwise we need to add it to the free qubits list. + if (!MayExtendCapacity) { - // If we are allowed to extend capacity we will never reuse this qubit, - // otherwise we need to add it to the free qubits list. - if (!MayExtendCapacity) + if (qubits[freeTail] != None) { - if (qubits[freeTail] != None) - { - // There were no free qubits at all - free = qubit.Id; - } - else - { - qubits[freeTail] = qubit.Id; - } + // There were no free qubits at all + free = qubit.Id; + } + else + { + qubits[freeTail] = qubit.Id; } - qubits[qubit.Id] = None; - freeTail = qubit.Id; } - - NumAllocatedQubits--; - Debug.Assert(NumAllocatedQubits >= 0); + qubits[qubit.Id] = None; + freeTail = qubit.Id; } + NumAllocatedQubits--; + Debug.Assert(NumAllocatedQubits >= 0); + if (!DisableBorrowing) { bool success = curFrame.Locals.Remove(qubit); @@ -489,7 +501,7 @@ protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing = /// public void Release(Qubit qubit) { - ReleaseOneQubit(qubit); + Release(qubit, wasUsedOnlyForBorrowing: false); } /// @@ -504,7 +516,7 @@ public void Release(IQArray qubitsToRelease) for (long i = qubitsToRelease.Length-1; i>=0; i--) { // Going from the end is more efficient in case we are tracking scope. - this.ReleaseOneQubit(qubitsToRelease[i]); + this.Release(qubitsToRelease[i], wasUsedOnlyForBorrowing: false); } } @@ -512,75 +524,82 @@ public void Release(IQArray qubitsToRelease) #region Borrow - protected virtual Qubit BorrowOneQubit(long id) - { - if (IsAllocatedForBorrowing(id)) - { - qubits[id]++; - } - - Qubit ret = CreateQubitObject(id); - if (!DisableBorrowing) - { - curFrame.Locals.Add(ret); - } - return ret; - } - - internal long TryBorrow(QArray borrowed, IEnumerable excludedQubitsSortedById) + /// + /// Returns a qubit that is free, not disabled, and not listed as in use, whose id is in [minId, maxId). + /// + /// Contains the qubits that cannot be borrowed, where the qubits with the lowest ids are queued first. + /// Only qubits whose id is larger or equal to minId will be considered for borrowing. Set to 0 if unspecified. + /// Only qubits whose id is smaller than maxId will be considered for borrowing. Set to NumQubits if unspecified. + /// + protected virtual Qubit Borrow(Stack qubitsInUseSortedById, long minId = 0, long maxId = -1) { - long curQubit = 0; - long curBorrowed = 0; - long numBorrowed = System.Math.Min(NumAllocatedQubits - excludedQubitsSortedById.Count(), borrowed.Length); - - IEnumerator enumer = excludedQubitsSortedById.GetEnumerator(); - bool exclusionsPresent = enumer.MoveNext(); - - while (curBorrowed < numBorrowed) + maxId = maxId < 0 ? NumQubits : maxId; + for (long curQubit = System.Math.Max(0, minId); curQubit < maxId; curQubit++) { while (IsFree(curQubit) || IsDisabled(curQubit)) { curQubit++; - Debug.Assert(curQubit < NumQubits); } - Debug.Assert((!exclusionsPresent) || (enumer.Current.Id >= curQubit)); - if ((!exclusionsPresent) || (enumer.Current.Id != curQubit)) + bool gotNextInUse = qubitsInUseSortedById.TryPeek(out Qubit nextInUse); + if (gotNextInUse && nextInUse.Id == curQubit) { - borrowed.Modify(curBorrowed, BorrowOneQubit(curQubit)); - curBorrowed++; + qubitsInUseSortedById.Pop(); + continue; } - else + + if (IsAllocatedForBorrowing(curQubit)) { - exclusionsPresent = enumer.MoveNext(); + qubits[curQubit]++; } - curQubit++; - Debug.Assert(curQubit < NumQubits); + + Qubit ret = CreateQubitObject(curQubit); + if (!DisableBorrowing) + { + curFrame.Locals.Add(ret); + } + return ret; + } + return null; + } + + // internal for testing purposes + internal IQArray Borrow(long numToBorrow, IEnumerable qubitsInUse) + { + var inUse = new Stack(qubitsInUse.Distinct().OrderByDescending(q => q.Id)); + var borrowed = QArray.Create(numToBorrow); + long numBorrowed = System.Math.Min(NumAllocatedQubits - inUse.Count, numToBorrow); + + long lastBorrowedId = -1; + for (long curBorrowed = 0; curBorrowed < numBorrowed; ++curBorrowed) + { + borrowed.Modify(curBorrowed, Borrow(inUse, minId: lastBorrowedId + 1)); + lastBorrowedId = borrowed[curBorrowed].Id; } - if (numBorrowed < borrowed.Length) + if (numBorrowed < numToBorrow) { // Not enough qubits to borrow. Allocate what was not borrowed. - for (long i = numBorrowed; i < borrowed.Length; i++) + for (long i = numBorrowed; i < numToBorrow; i++) { - borrowed.Modify(i, AllocateOneQubit(usedOnlyForBorrowing: true)); + borrowed.Modify(i, Allocate(usedOnlyForBorrowing: true)); if (borrowed[(int)i] == null) { for (long k = numBorrowed; k < i; k++) { - ReleaseOneQubit(borrowed[(int)k], usedOnlyForBorrowing: true); + Release(borrowed[(int)k], wasUsedOnlyForBorrowing: true); } - throw new NotEnoughQubits(borrowed.Length, numBorrowed + GetFreeQubitsCount()); + throw new NotEnoughQubits(numToBorrow, numBorrowed + GetFreeQubitsCount()); } } } - return numBorrowed; + return borrowed; } /// /// Borrows a number of qubits. Chooses them from among already allocated ones. /// If there are not enough qubits to borrow, allocates new ones. /// - public virtual IQArray Borrow(long numToBorrow) + public IQArray Borrow(long numToBorrow) { if (numToBorrow < 0) { @@ -596,57 +615,23 @@ public virtual IQArray Borrow(long numToBorrow) return Allocate(numToBorrow); } - QArray result = QArray.Create(numToBorrow); - _ = TryBorrow(result, ConstructExcludedQubitsArray(curFrame)); - return result; + return Borrow(numToBorrow, QubitsInUse(curFrame)); } public Qubit Borrow() { - return this.Borrow(1)[0]; - } - - #endregion - - protected virtual void ReturnOneQubit(Qubit qubit) - { - if (!DisableBorrowing) + if (DisableBorrowing) { - bool success = curFrame.Locals.Remove(qubit); // Could be more efficient here going from the end manually. - Debug.Assert(success, "Returning qubit that is not a local variable in scope."); + return Allocate(); } - } - /// - /// Returns true if a qubit has been allocated just for borrowing, has been borrowed exactly once, - /// and thus will be released after it is returned. - /// - public virtual bool ToBeReleasedAfterReturn(Qubit qubit) - { - return IsAllocatedForBorrowing(qubit.Id) && qubits[qubit.Id] == AllocatedForBorrowing; + var inUse = new Stack(QubitsInUse(curFrame).Distinct().OrderByDescending(q => q.Id)); + return NumAllocatedQubits == inUse.Count ? Allocate() : (Borrow(inUse) ?? Allocate()); } - /// - /// Returns a count of input qubits that have been allocated just for borrowing, borrowed exactly once, - /// and thus will be released after they are returned. - /// - public virtual long ToBeReleasedAfterReturnCount(IQArray qubitsToReturn) - { - if (qubitsToReturn == null || qubitsToReturn.Length == 0) - { - return 0; - } + #endregion - long count = 0; - foreach (Qubit qubit in qubitsToReturn) - { - if (this.ToBeReleasedAfterReturn(qubit)) - { - count++; - } - } - return count; - } + #region Return /// /// Returns a given borrowed qubit. @@ -656,7 +641,7 @@ public virtual void Return(Qubit qubit) { if (DisableBorrowing) { - this.ReleaseOneQubit(qubit); + this.Release(qubit, wasUsedOnlyForBorrowing: false); } else { @@ -675,11 +660,12 @@ public virtual void Return(Qubit qubit) if (needsToBeReleased) { - this.ReleaseOneQubit(qubit, usedOnlyForBorrowing: true); + this.Release(qubit, wasUsedOnlyForBorrowing: true); } else { - this.ReturnOneQubit(qubit); + bool success = curFrame.Locals.Remove(qubit); // Could be more efficient here going from the end manually. + Debug.Assert(success, "Returning qubit that is not a local variable in scope."); } } } @@ -702,4 +688,5 @@ public void Return(IQArray qubitsToReturn) } } + #endregion } diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs index 84e8c3d4191..86009c18467 100644 --- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs +++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs @@ -64,14 +64,12 @@ public void TestQubitManager() long qubitsAvailable; qubitsAvailable = qm.GetFreeQubitsCount(); - QArray qab = QArray.Create(5); - long nrBorrowed = qm.TryBorrow(qab, exclusion); - Assert.Equal(4, nrBorrowed); + IQArray qab = qm.Borrow(5, exclusion); Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); Assert.True(qab[0].Id == 0); Assert.True(qab[1].Id == 2); Assert.True(qab[2].Id == 4); - Assert.True(qab[3].Id == 5); + Assert.True(qab[3].Id == 7); Assert.True(qab[4].Id == 8); Qubit q6 = qm.Allocate(); @@ -79,9 +77,7 @@ public void TestQubitManager() // Test borrowing of the same qubit again qubitsAvailable = qm.GetFreeQubitsCount(); - QArray qb1 = QArray.Create(1); - nrBorrowed = qm.TryBorrow(qb1, exclusion); - Assert.Equal(1, nrBorrowed); + IQArray qb1 = qm.Borrow(1, exclusion); Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 0); Assert.True(qb1[0].Id == 0); qm.Return(qb1[0]); @@ -123,8 +119,7 @@ public void TestQubitManager() IQArray n_q; n_q = qm.Allocate(0); Assert.True(n_q.Length == 0); - nrBorrowed = qm.TryBorrow(new QArray(), exclusion); - Assert.Equal(0, nrBorrowed); + n_q = qm.Borrow(0, exclusion); Assert.True(n_q.Length == 0); } diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs index 76e31e9204f..06fc6f64697 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs @@ -51,16 +51,16 @@ public override Qubit CreateQubitObject(long id) return new QSimQubit((int)id, SimulatorId); } - protected override Qubit AllocateOneQubit(bool usedOnlyForBorrowing) + protected override Qubit Allocate(bool usedOnlyForBorrowing) { - Qubit qubit = base.AllocateOneQubit(usedOnlyForBorrowing); + Qubit qubit = base.Allocate(usedOnlyForBorrowing); if (qubit != null) { AllocateOne(this.SimulatorId, (uint)qubit.Id); } return qubit; } - protected override void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing) + protected override void Release(Qubit qubit, bool wasUsedOnlyForBorrowing) { - base.ReleaseOneQubit(qubit, usedOnlyForBorrowing); + base.Release(qubit, wasUsedOnlyForBorrowing); if (qubit != null) { bool isReleasedQubitZero = ReleaseOne(this.SimulatorId, (uint)qubit.Id); From 5a1b79d40f905c05ffcf86f81e3458ee6500b08f Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 18:55:42 -0700 Subject: [PATCH 08/20] qubit manager should now be in a good state --- src/Simulation/Common/IQuantumProcessor.cs | 1 - src/Simulation/Common/IQubitManager.cs | 31 ++++++------ src/Simulation/Common/QubitManager.cs | 49 ++++++------------- src/Simulation/Common/SimulatorBase.cs | 6 +-- .../Simulators/QuantumProcessor/Borrow.cs | 6 +-- .../QuantumProcessorDispatcher.cs | 9 ++-- .../Simulators/QuantumProcessor/Return.cs | 10 ++-- 7 files changed, 44 insertions(+), 68 deletions(-) diff --git a/src/Simulation/Common/IQuantumProcessor.cs b/src/Simulation/Common/IQuantumProcessor.cs index dd61aed3bdd..ed6d7fcc3eb 100644 --- a/src/Simulation/Common/IQuantumProcessor.cs +++ b/src/Simulation/Common/IQuantumProcessor.cs @@ -11,7 +11,6 @@ namespace Microsoft.Quantum.Simulation.Common /// /// /// To implement a target machine that executes quantum commands, implement this interface. - /// Consider using as a stub for easy impementation of this interface. /// Implementors of interface do not manage qubits on their own. /// All qubit management (allocation, dealocation, etc.) is done by the caller of this interface. /// Implementors are notified when qubits are allocated, released, borrowed and returned allowing them to react to these events if necessary. diff --git a/src/Simulation/Common/IQubitManager.cs b/src/Simulation/Common/IQubitManager.cs index 0c8cd255f42..7300f5ea221 100644 --- a/src/Simulation/Common/IQubitManager.cs +++ b/src/Simulation/Common/IQubitManager.cs @@ -8,35 +8,32 @@ namespace Microsoft.Quantum.Simulation.Common public interface IQubitManager { + bool DisableBorrowing { get; } + + bool IsValid(Qubit qubit); + bool IsFree(Qubit qubit); + bool IsDisabled(Qubit qubit); + + long GetFreeQubitsCount(); + long GetQubitsAvailableToBorrowCount(int stackFrame = 0); + long GetAllocatedQubitsCount(); + IEnumerable GetAllocatedIds(); + + void Disable(Qubit qubit); + void Disable(IQArray qubits); + Qubit Allocate(); IQArray Allocate(long count); void Release(Qubit qubit); void Release(IQArray qubits); - void Disable(Qubit qubit); - void Disable(IQArray qubits); - Qubit Borrow(); IQArray Borrow(long count); void Return(Qubit q); void Return(IQArray qubits); - bool ToBeReleasedAfterReturn(Qubit qubit); - long ToBeReleasedAfterReturnCount(IQArray qubitsToReturn); - - bool IsValid(Qubit qubit); - bool IsFree(Qubit qubit); - bool IsDisabled(Qubit qubit); - - long GetFreeQubitsCount(); - long GetQubitsAvailableToBorrowCount(); - long GetAllocatedQubitsCount(); - IEnumerable GetAllocatedIds(); - - bool DisableBorrowing { get; } - /// /// Callback to notify QubitManager that an operation execution has started. /// This helps manage qubits scope. diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index b2fddcc256d..9c38a9e0ab0 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -237,9 +237,23 @@ private bool IsAllocatedForBorrowing(long id) return qubits[id] >= AllocatedForBorrowing; } - public virtual long GetQubitsAvailableToBorrowCount() + public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) { - return DisableBorrowing ? 0 : NumAllocatedQubits - QubitsInUseCount(curFrame); + StackFrame frame = curFrame; + if (stackFrame > 0) + { + var popped = new Stack(); + while (--stackFrame > 0) + { + popped.Push(operationStack.Pop()); + } + frame = operationStack.Peek(); + while (popped.TryPop(out var f)) + { + operationStack.Push(f); + } + } + return DisableBorrowing ? 0 : NumAllocatedQubits - QubitsInUseCount(frame); } public long GetFreeQubitsCount() @@ -260,37 +274,6 @@ public virtual IEnumerable GetAllocatedIds() } } - /// - /// Returns true if a qubit has been allocated just for borrowing, has been borrowed exactly once, - /// and thus will be released after it is returned. - /// - public virtual bool ToBeReleasedAfterReturn(Qubit qubit) - { - return IsAllocatedForBorrowing(qubit.Id) && qubits[qubit.Id] == AllocatedForBorrowing; - } - - /// - /// Returns a count of input qubits that have been allocated just for borrowing, borrowed exactly once, - /// and thus will be released after they are returned. - /// - public virtual long ToBeReleasedAfterReturnCount(IQArray qubitsToReturn) - { - if (qubitsToReturn == null || qubitsToReturn.Length == 0) - { - return 0; - } - - long count = 0; - foreach (Qubit qubit in qubitsToReturn) - { - if (this.ToBeReleasedAfterReturn(qubit)) - { - count++; - } - } - return count; - } - #region Disable /// diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index c38fc99d7d4..8ee9094762f 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -31,14 +31,11 @@ public abstract class SimulatorBase : Factory, IOperationFacto public event Action? OnLog = null; public event Action>? OnException = null; - protected readonly int randomSeed; protected readonly Lazy randomGenerator; public int Seed => randomSeed; protected System.Random RandomGenerator => randomGenerator.Value; - - /// /// An event fired whenever a simulator has additional diagnostic data /// available for display (e.g. state information, assertion details, @@ -50,7 +47,6 @@ public abstract class SimulatorBase : Factory, IOperationFacto public abstract string Name { get; } - /// /// If the execution finishes in failure, this method returns the call-stack of the Q# operations /// executed up to the point when the failure happened. @@ -429,7 +425,7 @@ public GetQubitsAvailableToBorrow(SimulatorBase m) : base(m) sim = m; } - public override Func __Body__ => (arg) => sim.QubitManager.GetQubitsAvailableToBorrowCount(); + public override Func __Body__ => (arg) => sim.QubitManager.GetQubitsAvailableToBorrowCount(1); } /// diff --git a/src/Simulation/Simulators/QuantumProcessor/Borrow.cs b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs index d497549ccb9..e5700cc8b8d 100644 --- a/src/Simulation/Simulators/QuantumProcessor/Borrow.cs +++ b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs @@ -17,10 +17,10 @@ public QuantumProcessorDispatcherBorrow(QuantumProcessorDispatcher m) : base(m){ public override Qubit Apply() { long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); - IQArray qubits = sim.QubitManager.Borrow(1); + Qubit qubit = sim.QubitManager.Borrow(); long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); - sim.QuantumProcessor.OnBorrowQubits(qubits, allocatedAfter - allocatedBefore); - return qubits[0]; + sim.QuantumProcessor.OnBorrowQubits(new QArray(qubit), allocatedAfter - allocatedBefore); + return qubit; } public override IQArray Apply(long count) diff --git a/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs index ca4235c4fbf..0865e201a4e 100644 --- a/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs +++ b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using Microsoft.Quantum.Simulation.Common; namespace Microsoft.Quantum.Simulation.QuantumProcessor @@ -27,10 +26,10 @@ public IQuantumProcessor QuantumProcessor /// /// /// - /// An instance of a class implementing interface to be wrapped. If the parameter is null is used. - /// An instance of a class implementing interface. If the parameter is null is used. + /// An instance of a class implementing interface to be wrapped. + /// An instance of a class implementing interface. If the parameter is null is used. /// A seed to be used by Q# Microsoft.Quantum.Intrinsic.Random operation. - public QuantumProcessorDispatcher(IQuantumProcessor? quantumProcessor = null, IQubitManager? qubitManager = null, int? randomSeed = null) + public QuantumProcessorDispatcher(IQuantumProcessor quantumProcessor, IQubitManager? qubitManager = null, int? randomSeed = null) : base( qubitManager ?? new QubitManager( PreallocatedQubitCount, @@ -39,7 +38,7 @@ public QuantumProcessorDispatcher(IQuantumProcessor? quantumProcessor = null, IQ randomSeed ) { - QuantumProcessor = quantumProcessor ?? new QuantumProcessorBase(); + QuantumProcessor = quantumProcessor; OnOperationStart += QuantumProcessor.OnOperationStart; OnOperationEnd += QuantumProcessor.OnOperationEnd; OnFail += QuantumProcessor.OnFail; diff --git a/src/Simulation/Simulators/QuantumProcessor/Return.cs b/src/Simulation/Simulators/QuantumProcessor/Return.cs index 2a5277340fd..a4aa62ada60 100644 --- a/src/Simulation/Simulators/QuantumProcessor/Return.cs +++ b/src/Simulation/Simulators/QuantumProcessor/Return.cs @@ -16,16 +16,18 @@ public QuantumProcessorDispatcherReturn(QuantumProcessorDispatcher m) : base(m){ public override void Apply(Qubit q) { - long count = (sim.QubitManager.ToBeReleasedAfterReturn(q) ? 1 : 0); - sim.QuantumProcessor.OnReturnQubits(new QArray(q), count); + long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); sim.QubitManager.Return(q); + long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + sim.QuantumProcessor.OnReturnQubits(new QArray(q), allocatedBefore - allocatedAfter); } public override void Apply(IQArray qubits) { - long count = sim.QubitManager.ToBeReleasedAfterReturnCount(qubits); - sim.QuantumProcessor.OnReturnQubits(qubits, count); + long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); sim.QubitManager.Return(qubits); + long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + sim.QuantumProcessor.OnReturnQubits(qubits, allocatedBefore - allocatedAfter); } } } From e6c0302ae67f11448509b3f29a44cca0ed9cb20e Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 19:00:01 -0700 Subject: [PATCH 09/20] removing the base class that just throws --- src/Simulation/Common/QuantumProcessorBase.cs | 303 ------------------ 1 file changed, 303 deletions(-) delete mode 100644 src/Simulation/Common/QuantumProcessorBase.cs diff --git a/src/Simulation/Common/QuantumProcessorBase.cs b/src/Simulation/Common/QuantumProcessorBase.cs deleted file mode 100644 index 26783f7fdea..00000000000 --- a/src/Simulation/Common/QuantumProcessorBase.cs +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using Microsoft.Quantum.Simulation.Core; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace Microsoft.Quantum.Simulation.Common -{ - /// - /// A class that implements IQuantumProcessor that does not do any logic, but is convenient to inherit from. - /// It throws for most APIs. - /// - public class QuantumProcessorBase : IQuantumProcessor - { - public virtual void X(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledX(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void Y(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledY(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void Z(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledZ(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void SWAP(Qubit qubit1, Qubit qubit2) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2) - { - throw new UnsupportedOperationException(); - } - - public virtual void H(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledH(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void S(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledS(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void SAdjoint(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledSAdjoint(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void T(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledT(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void TAdjoint(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledTAdjoint(IQArray controls, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void R(Pauli axis, double theta, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void RFrac(Pauli axis, long numerator, long power, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void R1(double theta, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledR1(IQArray controls, double theta, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void R1Frac(long numerator, long power, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual void Exp(IQArray paulis, double theta, IQArray qubits) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits) - { - throw new UnsupportedOperationException(); - } - - public virtual void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits) - { - throw new UnsupportedOperationException(); - } - - public virtual void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits) - { - throw new UnsupportedOperationException(); - } - - public virtual Result M(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual Result Measure(IQArray bases, IQArray qubits) - { - throw new UnsupportedOperationException(); - } - - public virtual void Reset(Qubit qubit) - { - throw new UnsupportedOperationException(); - } - - public virtual long StartConditionalStatement(IQArray measurementResults, IQArray resultsValues) - { - if (measurementResults == null) { return 1; }; - if (resultsValues == null) { return 1; }; - Debug.Assert(measurementResults.Count == resultsValues.Count); - if (measurementResults.Count != resultsValues.Count) { return 1; }; - - int equal = 1; - - for (int i = 0; i < measurementResults.Count; i++) - { - if (measurementResults[i] != resultsValues[i]) - { - equal = 0; - } - } - - return equal; - } - - public virtual long StartConditionalStatement(Result measurementResult, Result resultValue) - { - - if (measurementResult == resultValue) - { - return 1; - } - else - { - return 0; - } - } - - public virtual bool RunThenClause(long statement) - { - return (statement != 0); - } - - public virtual bool RepeatThenClause(long statement) - { - return false; - } - - public virtual bool RunElseClause(long statement) - { - return (statement == 0); - } - - public virtual bool RepeatElseClause(long statement) - { - return false; - } - - public virtual void EndConditionalStatement(long id) - { - - } - - public virtual void Assert(IQArray bases, IQArray qubits, Result result, string msg) - { - } - - public virtual void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol) - { - } - - public virtual void OnOperationStart(ICallable operation, IApplyData arguments) - { - } - - public virtual void OnOperationEnd(ICallable operation, IApplyData arguments) - { - } - - public virtual void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo) - { - } - - public virtual void OnAllocateQubits(IQArray qubits) - { - } - - public virtual void OnReleaseQubits(IQArray qubits) - { - } - - public virtual void OnBorrowQubits(IQArray qubits, long allocatedForBorrowingCount) - { - } - - public virtual void OnReturnQubits(IQArray qubits, long releasedOnReturnCount) - { - } - - public virtual void OnDumpMachine(T location) - { - } - - public virtual void OnDumpRegister(T location, IQArray qubits) - { - } - - public virtual void OnMessage(string msg) - { - } - - } - - /// - /// A class that implements exception to be thrown when Operation is not supported by a QuantumProcessor. - /// - public class UnsupportedOperationException : PlatformNotSupportedException - { - public UnsupportedOperationException(string text = "", - [CallerFilePath] string file = "", - [CallerMemberName] string member = "", - [CallerLineNumber] int line = 0) - : base($"{file}::{line}::[{member}]:{text}") - { - } - } -} From 54f08c99b4a3cb569ddc3b8d1fb585e8eac2cc22 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 3 Sep 2020 23:43:59 -0700 Subject: [PATCH 10/20] forgot to adapt a test --- .../Simulators.Tests/Circuits/GetAvailableTest.qs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Simulation/Simulators.Tests/Circuits/GetAvailableTest.qs b/src/Simulation/Simulators.Tests/Circuits/GetAvailableTest.qs index 0016786c024..916792d3a07 100644 --- a/src/Simulation/Simulators.Tests/Circuits/GetAvailableTest.qs +++ b/src/Simulation/Simulators.Tests/Circuits/GetAvailableTest.qs @@ -9,22 +9,22 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { mutable innerBorrow = 0; borrowing (qb = Qubit()) { - set innerBorrow = GetQubitsAvailableToBorrow(); + set innerBorrow = GetQubitsAvailableToBorrow() + GetQubitsAvailableToUse(); } - return (GetQubitsAvailableToBorrow(), innerBorrow); + return (GetQubitsAvailableToBorrow() + GetQubitsAvailableToUse(), innerBorrow); } operation GetAvailableTest (allocSize : Int) : (Int, Int, Int, Int, Int, Int) { let initialUse = GetQubitsAvailableToUse(); - let initialBorrow = GetQubitsAvailableToBorrow(); + let initialBorrow = GetQubitsAvailableToBorrow() + initialUse; mutable result = (0, 0, 0, 0, 0, 0); using (qs = Qubit[allocSize]) { let afterUse = GetQubitsAvailableToUse(); - let afterBorrow = GetQubitsAvailableToBorrow(); + let afterBorrow = GetQubitsAvailableToBorrow() + afterUse; let (subBorrow, innerBorrow) = BorrowSubTest(); set result = (initialUse, initialBorrow, afterUse, afterBorrow, subBorrow, innerBorrow); } From 242de6a83d9359e3de1670d314eda509ef9f6564 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Fri, 4 Sep 2020 00:09:34 -0700 Subject: [PATCH 11/20] processor base --- src/Simulation/Common/QuantumProcessorBase.cs | 289 ++++++++++++++++++ src/Simulation/Common/SimulatorBase.cs | 15 + .../Microsoft.Quantum.CsharpGeneration.fsproj | 2 +- ....Simulation.QCTraceSimulatorRuntime.csproj | 2 +- .../Microsoft.Quantum.QSharp.Core.csproj | 2 +- .../HoneywellExe/HoneywellExe.csproj | 2 +- .../IntrinsicTests/IntrinsicTests.csproj | 2 +- .../TestProjects/IonQExe/IonQExe.csproj | 2 +- .../Library with Spaces.csproj | 2 +- .../TestProjects/Library1/Library1.csproj | 2 +- .../TestProjects/Library2/Library2.csproj | 2 +- .../TestProjects/QCIExe/QCIExe.csproj | 2 +- .../TestProjects/QsharpExe/QsharpExe.csproj | 2 +- .../TargetedExe/TargetedExe.csproj | 2 +- .../TestProjects/UnitTests/UnitTests.csproj | 2 +- .../Tests.Microsoft.Quantum.Simulators.csproj | 2 +- .../Microsoft.Quantum.Simulators.csproj | 2 +- 17 files changed, 319 insertions(+), 15 deletions(-) create mode 100644 src/Simulation/Common/QuantumProcessorBase.cs diff --git a/src/Simulation/Common/QuantumProcessorBase.cs b/src/Simulation/Common/QuantumProcessorBase.cs new file mode 100644 index 00000000000..7b1010ea224 --- /dev/null +++ b/src/Simulation/Common/QuantumProcessorBase.cs @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; +using System.Diagnostics; + +namespace Microsoft.Quantum.Simulation.Common +{ + /// + /// A class that implements IQuantumProcessor that does not do any logic, but is convenient to inherit from. + /// It throws for most APIs. + /// + [Obsolete] + public class QuantumProcessorBase : IQuantumProcessor + { + public virtual void X(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledX(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void Y(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledY(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void Z(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledZ(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void SWAP(Qubit qubit1, Qubit qubit2) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2) + { + throw new UnsupportedOperationException(); + } + + public virtual void H(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledH(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void S(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledS(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void SAdjoint(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledSAdjoint(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void T(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledT(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void TAdjoint(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledTAdjoint(IQArray controls, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void R(Pauli axis, double theta, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void RFrac(Pauli axis, long numerator, long power, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void R1(double theta, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledR1(IQArray controls, double theta, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void R1Frac(long numerator, long power, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual void Exp(IQArray paulis, double theta, IQArray qubits) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits) + { + throw new UnsupportedOperationException(); + } + + public virtual void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new UnsupportedOperationException(); + } + + public virtual void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new UnsupportedOperationException(); + } + + public virtual Result M(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual Result Measure(IQArray bases, IQArray qubits) + { + throw new UnsupportedOperationException(); + } + + public virtual void Reset(Qubit qubit) + { + throw new UnsupportedOperationException(); + } + + public virtual long StartConditionalStatement(IQArray measurementResults, IQArray resultsValues) + { + if (measurementResults == null) { return 1; }; + if (resultsValues == null) { return 1; }; + Debug.Assert(measurementResults.Count == resultsValues.Count); + if (measurementResults.Count != resultsValues.Count) { return 1; }; + + int equal = 1; + + for (int i = 0; i < measurementResults.Count; i++) + { + if (measurementResults[i] != resultsValues[i]) + { + equal = 0; + } + } + + return equal; + } + + public virtual long StartConditionalStatement(Result measurementResult, Result resultValue) + { + + if (measurementResult == resultValue) + { + return 1; + } + else + { + return 0; + } + } + + public virtual bool RunThenClause(long statement) + { + return (statement != 0); + } + + public virtual bool RepeatThenClause(long statement) + { + return false; + } + + public virtual bool RunElseClause(long statement) + { + return (statement == 0); + } + + public virtual bool RepeatElseClause(long statement) + { + return false; + } + + public virtual void EndConditionalStatement(long id) + { + + } + + public virtual void Assert(IQArray bases, IQArray qubits, Result result, string msg) + { + } + + public virtual void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol) + { + } + + public virtual void OnOperationStart(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnOperationEnd(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo) + { + } + + public virtual void OnAllocateQubits(IQArray qubits) + { + } + + public virtual void OnReleaseQubits(IQArray qubits) + { + } + + public virtual void OnBorrowQubits(IQArray qubits, long allocatedForBorrowingCount) + { + } + + public virtual void OnReturnQubits(IQArray qubits, long releasedOnReturnCount) + { + } + + public virtual void OnDumpMachine(T location) + { + } + + public virtual void OnDumpRegister(T location, IQArray qubits) + { + } + + public virtual void OnMessage(string msg) + { + } + + } +} diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index 8ee9094762f..d6d7fb98fac 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Quantum.Simulation.Core; @@ -12,6 +13,20 @@ namespace Microsoft.Quantum.Simulation.Common { + /// + /// A class that implements exception to be thrown when Operation is not supported by a QuantumProcessor. + /// + public class UnsupportedOperationException : PlatformNotSupportedException + { + public UnsupportedOperationException(string text = "", + [CallerFilePath] string file = "", + [CallerMemberName] string member = "", + [CallerLineNumber] int line = 0) + : base($"{file}::{line}::[{member}]:{text}") + { + } + } + /// /// A Base class for Simulators. /// It provides the infrastructure that makes it easy for a Simulator diff --git a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj index b47f0af63be..69692852e39 100644 --- a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj +++ b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj @@ -21,7 +21,7 @@ - + diff --git a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj index ba121246d35..90e51fceefd 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj +++ b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj index 807c708c9b3..9c0779e106d 100644 --- a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj +++ b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj index 957ffe6c2bd..83279f630f9 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj index e85a1a19e96..554333cd5b7 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj index 5ac7dcf5f7e..81643813a53 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj index ebdaa51f4c0..932a1b7626f 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 false diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj index 56799905ef0..f0a718032f9 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj index 56799905ef0..f0a718032f9 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj index df2e5362b29..e6642928821 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj index 283f23eec8b..756e9f1505a 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj index 682391cfdac..61cd41da21b 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj index 22e1d8d901d..2c37ed8b3b9 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj index 6fa960aef8f..4fe8bfbf072 100644 --- a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj index 25a7446c6f1..579161fc674 100644 --- a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + From ec819c4568e0bc4023cf92b26d08525f0dd02e06 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Mon, 7 Sep 2020 15:49:42 -0700 Subject: [PATCH 12/20] removing accidental commit --- src/Simulation/Common/QuantumProcessorBase.cs | 16 +++++++++++++++- src/Simulation/Common/SimulatorBase.cs | 15 --------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Simulation/Common/QuantumProcessorBase.cs b/src/Simulation/Common/QuantumProcessorBase.cs index 7b1010ea224..26783f7fdea 100644 --- a/src/Simulation/Common/QuantumProcessorBase.cs +++ b/src/Simulation/Common/QuantumProcessorBase.cs @@ -4,6 +4,7 @@ using System; using Microsoft.Quantum.Simulation.Core; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace Microsoft.Quantum.Simulation.Common { @@ -11,7 +12,6 @@ namespace Microsoft.Quantum.Simulation.Common /// A class that implements IQuantumProcessor that does not do any logic, but is convenient to inherit from. /// It throws for most APIs. /// - [Obsolete] public class QuantumProcessorBase : IQuantumProcessor { public virtual void X(Qubit qubit) @@ -286,4 +286,18 @@ public virtual void OnMessage(string msg) } } + + /// + /// A class that implements exception to be thrown when Operation is not supported by a QuantumProcessor. + /// + public class UnsupportedOperationException : PlatformNotSupportedException + { + public UnsupportedOperationException(string text = "", + [CallerFilePath] string file = "", + [CallerMemberName] string member = "", + [CallerLineNumber] int line = 0) + : base($"{file}::{line}::[{member}]:{text}") + { + } + } } diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index d6d7fb98fac..8ee9094762f 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Quantum.Simulation.Core; @@ -13,20 +12,6 @@ namespace Microsoft.Quantum.Simulation.Common { - /// - /// A class that implements exception to be thrown when Operation is not supported by a QuantumProcessor. - /// - public class UnsupportedOperationException : PlatformNotSupportedException - { - public UnsupportedOperationException(string text = "", - [CallerFilePath] string file = "", - [CallerMemberName] string member = "", - [CallerLineNumber] int line = 0) - : base($"{file}::{line}::[{member}]:{text}") - { - } - } - /// /// A Base class for Simulators. /// It provides the infrastructure that makes it easy for a Simulator From 72dfaa3bc0f0b59edaf18ddfb9d4ed5c5c80c96d Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Mon, 7 Sep 2020 16:42:18 -0700 Subject: [PATCH 13/20] wrong package nr --- .../CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj | 2 +- ....Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj | 2 +- src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj | 2 +- .../TestProjects/HoneywellExe/HoneywellExe.csproj | 2 +- .../TestProjects/IntrinsicTests/IntrinsicTests.csproj | 2 +- .../Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj | 2 +- .../TestProjects/Library with Spaces/Library with Spaces.csproj | 2 +- .../Simulators.Tests/TestProjects/Library1/Library1.csproj | 2 +- .../Simulators.Tests/TestProjects/Library2/Library2.csproj | 2 +- .../Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj | 2 +- .../Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj | 2 +- .../TestProjects/TargetedExe/TargetedExe.csproj | 2 +- .../Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj | 2 +- .../Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj | 2 +- src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj index 69692852e39..b47f0af63be 100644 --- a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj +++ b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj @@ -21,7 +21,7 @@ - + diff --git a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj index 90e51fceefd..ba121246d35 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj +++ b/src/Simulation/QCTraceSimulator.Tests/Tests.Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj index 9c0779e106d..807c708c9b3 100644 --- a/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj +++ b/src/Simulation/QsharpCore/Microsoft.Quantum.QSharp.Core.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj index 83279f630f9..957ffe6c2bd 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/HoneywellExe/HoneywellExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj index 554333cd5b7..e85a1a19e96 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/IntrinsicTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj index 81643813a53..5ac7dcf5f7e 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/IonQExe/IonQExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj index 932a1b7626f..ebdaa51f4c0 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library with Spaces/Library with Spaces.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 false diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj index f0a718032f9..56799905ef0 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library1/Library1.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj index f0a718032f9..56799905ef0 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/Library2/Library2.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 diff --git a/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj index e6642928821..df2e5362b29 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/QCIExe/QCIExe.csproj @@ -1,4 +1,4 @@ - + Library diff --git a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj index 756e9f1505a..283f23eec8b 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/QsharpExe/QsharpExe.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj b/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj index 61cd41da21b..682391cfdac 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/TargetedExe/TargetedExe.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj index 2c37ed8b3b9..22e1d8d901d 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj +++ b/src/Simulation/Simulators.Tests/TestProjects/UnitTests/UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj index 4fe8bfbf072..6fa960aef8f 100644 --- a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj index 579161fc674..25a7446c6f1 100644 --- a/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj +++ b/src/Simulation/Simulators/Microsoft.Quantum.Simulators.csproj @@ -1,4 +1,4 @@ - + From 6172760d90a50dfefd7a054ea299e7050be0f8f5 Mon Sep 17 00:00:00 2001 From: bettinaheim <34236215+bettinaheim@users.noreply.github.com> Date: Tue, 8 Sep 2020 17:46:44 -0700 Subject: [PATCH 14/20] Update src/Simulation/Common/AssemblyInfo.cs Co-authored-by: Chris Granade --- src/Simulation/Common/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/Common/AssemblyInfo.cs b/src/Simulation/Common/AssemblyInfo.cs index f9807358194..98a8d5a45f2 100644 --- a/src/Simulation/Common/AssemblyInfo.cs +++ b/src/Simulation/Common/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Runtime.CompilerServices; From 5818db9c1daf5e8703c90f3fc029272bc3b6bc9d Mon Sep 17 00:00:00 2001 From: bettinaheim <34236215+bettinaheim@users.noreply.github.com> Date: Tue, 8 Sep 2020 17:47:17 -0700 Subject: [PATCH 15/20] Update src/Simulation/Common/QubitManager.cs Co-authored-by: Chris Granade --- src/Simulation/Common/QubitManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 9c38a9e0ab0..474c5a755dd 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -81,12 +81,7 @@ protected class StackFrame internal IEnumerable QubitsInArgument => Data?.Qubits; internal List _locals; // Qubits allocated/borrowed in the current operation - public StackFrame() - { - Data = null; - } - - public StackFrame(IApplyData data) + public StackFrame(IApplyData data = null) { Data = data; } From 29b60888dfd6a7d686e4d3deb76d9aafebf308e4 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 9 Sep 2020 19:24:54 -0700 Subject: [PATCH 16/20] nullable enable --- src/Simulation/Common/QubitManager.cs | 39 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 9c38a9e0ab0..89138db9f64 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -8,6 +8,8 @@ using Microsoft.Quantum.Simulation.Core; using Microsoft.Quantum.Simulation.Simulators.Exceptions; +#nullable enable + namespace Microsoft.Quantum.Simulation.Common { /// @@ -77,9 +79,9 @@ private void UpdateQubitCapacity(long newQubitCapacity) protected class StackFrame { - internal IApplyData Data; - internal IEnumerable QubitsInArgument => Data?.Qubits; - internal List _locals; // Qubits allocated/borrowed in the current operation + internal IApplyData? Data; + internal IEnumerable? QubitsInArgument => Data?.Qubits; + private List? _locals; // Qubits allocated/borrowed in the current operation public StackFrame() { @@ -239,6 +241,11 @@ private bool IsAllocatedForBorrowing(long id) public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) { + if (DisableBorrowing) + { + return 0; + } + StackFrame frame = curFrame; if (stackFrame > 0) { @@ -253,7 +260,7 @@ public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) operationStack.Push(f); } } - return DisableBorrowing ? 0 : NumAllocatedQubits - QubitsInUseCount(frame); + return NumAllocatedQubits - QubitsInUseCount(frame); } public long GetFreeQubitsCount() @@ -314,7 +321,7 @@ 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) { @@ -388,7 +395,7 @@ protected virtual Qubit Allocate(bool usedOnlyForBorrowing) /// public Qubit Allocate() { - Qubit qb = Allocate(usedOnlyForBorrowing: false); + Qubit? qb = Allocate(usedOnlyForBorrowing: false); if (qb == null) { throw new NotEnoughQubits(1, GetFreeQubitsCount()); @@ -414,8 +421,8 @@ public IQArray Allocate(long numToAllocate) QArray result = QArray.Create(numToAllocate); for (int i = 0; i < numToAllocate; i++) { - result.Modify(i, Allocate(usedOnlyForBorrowing: false)); - if (result[i] == null) + Qubit? allocated = Allocate(usedOnlyForBorrowing: false); + if (allocated == null) { for (int k = 0; k < i; k++) { @@ -423,6 +430,7 @@ public IQArray Allocate(long numToAllocate) } throw new NotEnoughQubits(numToAllocate, GetFreeQubitsCount()); } + result.Modify(i, allocated); } return result; @@ -514,7 +522,7 @@ public void Release(IQArray qubitsToRelease) /// Only qubits whose id is larger or equal to minId will be considered for borrowing. Set to 0 if unspecified. /// Only qubits whose id is smaller than maxId will be considered for borrowing. Set to NumQubits if unspecified. /// - protected virtual Qubit Borrow(Stack qubitsInUseSortedById, long minId = 0, long maxId = -1) + protected virtual Qubit? Borrow(Stack qubitsInUseSortedById, long minId = 0, long maxId = -1) { maxId = maxId < 0 ? NumQubits : maxId; for (long curQubit = System.Math.Max(0, minId); curQubit < maxId; curQubit++) @@ -555,7 +563,13 @@ internal IQArray Borrow(long numToBorrow, IEnumerable qubitsInUse) long lastBorrowedId = -1; for (long curBorrowed = 0; curBorrowed < numBorrowed; ++curBorrowed) { - borrowed.Modify(curBorrowed, Borrow(inUse, minId: lastBorrowedId + 1)); + Qubit? bq = Borrow(inUse, minId: lastBorrowedId + 1); + if (bq == null) // should not happen + { + numBorrowed = curBorrowed; + break; + } + borrowed.Modify(curBorrowed, bq); lastBorrowedId = borrowed[curBorrowed].Id; } @@ -563,8 +577,8 @@ internal IQArray Borrow(long numToBorrow, IEnumerable qubitsInUse) { // Not enough qubits to borrow. Allocate what was not borrowed. for (long i = numBorrowed; i < numToBorrow; i++) { - borrowed.Modify(i, Allocate(usedOnlyForBorrowing: true)); - if (borrowed[(int)i] == null) + Qubit? allocated = Allocate(usedOnlyForBorrowing: true); + if (allocated == null) { for (long k = numBorrowed; k < i; k++) { @@ -572,6 +586,7 @@ internal IQArray Borrow(long numToBorrow, IEnumerable qubitsInUse) } throw new NotEnoughQubits(numToBorrow, numBorrowed + GetFreeQubitsCount()); } + borrowed.Modify(i, allocated); } } From 47601ba561b448eef8d1e2400cde0655241e9c8c Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Wed, 9 Sep 2020 20:10:02 -0700 Subject: [PATCH 17/20] review feedback --- src/Simulation/Common/QubitManager.cs | 49 ++++++++++++-------------- src/Simulation/Common/SimulatorBase.cs | 1 - 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 89138db9f64..1febae2330f 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -107,15 +107,13 @@ public List Locals } } - protected readonly Stack operationStack; // Stack of operation calls. - protected StackFrame curFrame; // Current stack frame - all qubits in current scope are listed here. + protected readonly Stack operationStack; // Stack of operation calls, including the current frame for the current scope public virtual void OnOperationStart(ICallable _, IApplyData values) { if (!DisableBorrowing) { - operationStack.Push(curFrame); - curFrame = new StackFrame(values); + operationStack.Push(new StackFrame(values)); } } @@ -123,7 +121,7 @@ public virtual void OnOperationEnd(ICallable _, IApplyData values) { if (!DisableBorrowing) { - curFrame = operationStack.Pop(); + operationStack.Pop(); } } @@ -179,7 +177,7 @@ public QubitManager( if (!DisableBorrowing) { operationStack = new Stack(); - curFrame = new StackFrame(); + operationStack.Push(new StackFrame()); } } @@ -246,19 +244,15 @@ public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) return 0; } - StackFrame frame = curFrame; - if (stackFrame > 0) + var popped = new Stack(); + while (--stackFrame > 0) { - var popped = new Stack(); - while (--stackFrame > 0) - { - popped.Push(operationStack.Pop()); - } - frame = operationStack.Peek(); - while (popped.TryPop(out var f)) - { - operationStack.Push(f); - } + popped.Push(operationStack.Pop()); + } + StackFrame frame = operationStack.Peek(); + while (popped.TryPop(out var f)) + { + operationStack.Push(f); } return NumAllocatedQubits - QubitsInUseCount(frame); } @@ -384,7 +378,7 @@ public void Disable(IQArray qubitsToDisable) NumAllocatedQubits++; if (!DisableBorrowing) { - curFrame.Locals.Add(ret); + operationStack.Peek().Locals.Add(ret); } return ret; } @@ -482,7 +476,7 @@ protected virtual void Release(Qubit qubit, bool wasUsedOnlyForBorrowing) if (!DisableBorrowing) { - bool success = curFrame.Locals.Remove(qubit); + bool success = operationStack.Peek().Locals.Remove(qubit); Debug.Assert(success, "Releasing qubit that is not a local variable in scope."); } } @@ -516,7 +510,7 @@ public void Release(IQArray qubitsToRelease) #region Borrow /// - /// Returns a qubit that is free, not disabled, and not listed as in use, whose id is in [minId, maxId). + /// Returns a qubit that is allocated, not disabled, and not listed as in use, whose id is in [minId, maxId). /// /// Contains the qubits that cannot be borrowed, where the qubits with the lowest ids are queued first. /// Only qubits whose id is larger or equal to minId will be considered for borrowing. Set to 0 if unspecified. @@ -527,10 +521,11 @@ public void Release(IQArray qubitsToRelease) maxId = maxId < 0 ? NumQubits : maxId; for (long curQubit = System.Math.Max(0, minId); curQubit < maxId; curQubit++) { - while (IsFree(curQubit) || IsDisabled(curQubit)) + if (IsFree(curQubit) || IsDisabled(curQubit)) { - curQubit++; + continue; } + bool gotNextInUse = qubitsInUseSortedById.TryPeek(out Qubit nextInUse); if (gotNextInUse && nextInUse.Id == curQubit) { @@ -546,7 +541,7 @@ public void Release(IQArray qubitsToRelease) Qubit ret = CreateQubitObject(curQubit); if (!DisableBorrowing) { - curFrame.Locals.Add(ret); + operationStack.Peek().Locals.Add(ret); } return ret; } @@ -613,7 +608,7 @@ public IQArray Borrow(long numToBorrow) return Allocate(numToBorrow); } - return Borrow(numToBorrow, QubitsInUse(curFrame)); + return Borrow(numToBorrow, QubitsInUse(operationStack.Peek())); } public Qubit Borrow() @@ -623,7 +618,7 @@ public Qubit Borrow() return Allocate(); } - var inUse = new Stack(QubitsInUse(curFrame).Distinct().OrderByDescending(q => q.Id)); + var inUse = new Stack(QubitsInUse(operationStack.Peek()).Distinct().OrderByDescending(q => q.Id)); return NumAllocatedQubits == inUse.Count ? Allocate() : (Borrow(inUse) ?? Allocate()); } @@ -662,7 +657,7 @@ public virtual void Return(Qubit qubit) } else { - bool success = curFrame.Locals.Remove(qubit); // Could be more efficient here going from the end manually. + bool success = operationStack.Peek().Locals.Remove(qubit); // Could be more efficient here going from the end manually. Debug.Assert(success, "Returning qubit that is not a local variable in scope."); } } diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index 8ee9094762f..9be5b2343a1 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Quantum.Simulation.Core; From 68d593eb40a70b0e1916cfd233a860417751c351 Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Thu, 10 Sep 2020 15:33:32 -0700 Subject: [PATCH 18/20] api change --- src/Simulation/Common/IQubitManager.cs | 8 +-- src/Simulation/Common/QubitManager.cs | 20 ++---- src/Simulation/Common/SimulatorBase.cs | 4 +- .../QCTraceSimulator/QCTraceSimulatorCore.cs | 12 ++-- .../Simulators.Tests/OperationsTestHelper.cs | 2 +- .../Simulators.Tests/QubitManagerTests.cs | 70 +++++++++---------- .../Simulators/QuantumProcessor/Borrow.cs | 8 +-- .../Simulators/QuantumProcessor/Return.cs | 8 +-- .../QuantumSimulator/QuantumSimulator.cs | 2 +- .../QuantumSimulator/StateDumper.cs | 2 +- .../Simulators/ToffoliSimulator/Dump.cs | 7 +- 11 files changed, 68 insertions(+), 75 deletions(-) diff --git a/src/Simulation/Common/IQubitManager.cs b/src/Simulation/Common/IQubitManager.cs index 7300f5ea221..f00ce28d8c0 100644 --- a/src/Simulation/Common/IQubitManager.cs +++ b/src/Simulation/Common/IQubitManager.cs @@ -14,10 +14,10 @@ public interface IQubitManager bool IsFree(Qubit qubit); bool IsDisabled(Qubit qubit); - long GetFreeQubitsCount(); - long GetQubitsAvailableToBorrowCount(int stackFrame = 0); - long GetAllocatedQubitsCount(); - IEnumerable GetAllocatedIds(); + long FreeQubitsCount { get; } + long AllocatedQubitsCount { get; } + IEnumerable AllocatedIds(); + long QubitsAvailableToBorrowCount(int stackFrame = 0); void Disable(Qubit qubit); void Disable(IQArray qubits); diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index 1febae2330f..c0127325847 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -237,7 +237,7 @@ private bool IsAllocatedForBorrowing(long id) return qubits[id] >= AllocatedForBorrowing; } - public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) + public virtual long QubitsAvailableToBorrowCount(int stackFrame) { if (DisableBorrowing) { @@ -257,17 +257,11 @@ public virtual long GetQubitsAvailableToBorrowCount(int stackFrame) return NumAllocatedQubits - QubitsInUseCount(frame); } - public long GetFreeQubitsCount() - { - return NumQubits - NumDisabledQubits - NumAllocatedQubits; - } + public long FreeQubitsCount => NumQubits - NumDisabledQubits - NumAllocatedQubits; - public long GetAllocatedQubitsCount() - { - return NumAllocatedQubits; - } + public long AllocatedQubitsCount => NumAllocatedQubits; - public virtual IEnumerable GetAllocatedIds() + public virtual IEnumerable AllocatedIds() { for (long i = 0; i < qubits.LongLength; i++) { @@ -392,7 +386,7 @@ public Qubit Allocate() Qubit? qb = Allocate(usedOnlyForBorrowing: false); if (qb == null) { - throw new NotEnoughQubits(1, GetFreeQubitsCount()); + throw new NotEnoughQubits(1, this.FreeQubitsCount); } return qb; } @@ -422,7 +416,7 @@ public IQArray Allocate(long numToAllocate) { Release(result[k], wasUsedOnlyForBorrowing: false); } - throw new NotEnoughQubits(numToAllocate, GetFreeQubitsCount()); + throw new NotEnoughQubits(numToAllocate, this.FreeQubitsCount); } result.Modify(i, allocated); } @@ -579,7 +573,7 @@ internal IQArray Borrow(long numToBorrow, IEnumerable qubitsInUse) { Release(borrowed[(int)k], wasUsedOnlyForBorrowing: true); } - throw new NotEnoughQubits(numToBorrow, numBorrowed + GetFreeQubitsCount()); + throw new NotEnoughQubits(numToBorrow, numBorrowed + this.FreeQubitsCount); } borrowed.Modify(i, allocated); } diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index 9be5b2343a1..a05d0faae1f 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -409,7 +409,7 @@ public GetQubitsAvailableToUse(SimulatorBase m) : base(m) sim = m; } - public override Func __Body__ => (arg) => sim.QubitManager.GetFreeQubitsCount(); + public override Func __Body__ => (arg) => sim.QubitManager.FreeQubitsCount; } /// @@ -424,7 +424,7 @@ public GetQubitsAvailableToBorrow(SimulatorBase m) : base(m) sim = m; } - public override Func __Body__ => (arg) => sim.QubitManager.GetQubitsAvailableToBorrowCount(1); + public override Func __Body__ => (arg) => sim.QubitManager.QubitsAvailableToBorrowCount(1); } /// diff --git a/src/Simulation/QCTraceSimulator/QCTraceSimulatorCore.cs b/src/Simulation/QCTraceSimulator/QCTraceSimulatorCore.cs index 87c56594945..281087f62a5 100644 --- a/src/Simulation/QCTraceSimulator/QCTraceSimulatorCore.cs +++ b/src/Simulation/QCTraceSimulator/QCTraceSimulatorCore.cs @@ -141,9 +141,9 @@ public IQArray Allocate(long count) public IQArray Borrow(long count) { - long qubitBeforeBorrow = qubitManager.GetAllocatedQubitsCount(); + long qubitBeforeBorrow = qubitManager.AllocatedQubitsCount; IQArray res = qubitManager.Borrow(count); - long newQubitsAllocated = qubitManager.GetAllocatedQubitsCount() - qubitBeforeBorrow; + long newQubitsAllocated = qubitManager.AllocatedQubitsCount - qubitBeforeBorrow; object[][] tracingData = GetTracingData(res); for (int i = 0; i < listeners.Length; ++i) @@ -158,9 +158,9 @@ public void Return(Qubit qubit) { Debug.Assert(qubit != null); - long qubitBeforeBorrow = qubitManager.GetAllocatedQubitsCount(); + long qubitBeforeBorrow = qubitManager.AllocatedQubitsCount; qubitManager.Return(qubit); - long qubitsReleased = qubitBeforeBorrow - qubitManager.GetAllocatedQubitsCount(); + long qubitsReleased = qubitBeforeBorrow - qubitManager.AllocatedQubitsCount; object[][] tracingData = GetTracingData(new QArray(qubit)); for (int i = 0; i < listeners.Length; ++i) @@ -173,9 +173,9 @@ public void Return(IQArray qubits) { Debug.Assert(qubits != null); - long qubitBeforeBorrow = qubitManager.GetAllocatedQubitsCount(); + long qubitBeforeBorrow = qubitManager.AllocatedQubitsCount; qubitManager.Return(qubits); - long qubitsReleased = qubitBeforeBorrow - qubitManager.GetAllocatedQubitsCount(); + long qubitsReleased = qubitBeforeBorrow - qubitManager.AllocatedQubitsCount; object[][] tracingData = GetTracingData(qubits); for (int i = 0; i < listeners.Length; ++i) diff --git a/src/Simulation/Simulators.Tests/OperationsTestHelper.cs b/src/Simulation/Simulators.Tests/OperationsTestHelper.cs index a14adfa3021..bde77e602d8 100644 --- a/src/Simulation/Simulators.Tests/OperationsTestHelper.cs +++ b/src/Simulation/Simulators.Tests/OperationsTestHelper.cs @@ -293,7 +293,7 @@ internal static void ctrlOnReleasedCtrlQubitTest(SimulatorBase sim, Action<(IQAr internal static void CheckNoQubitLeak(this SimulatorBase sim) { - Assert.True(sim.QubitManager.GetAllocatedQubitsCount() == 0); + Assert.True(sim.QubitManager.AllocatedQubitsCount == 0); } /// diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs index 86009c18467..e47cabe899e 100644 --- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs +++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs @@ -63,9 +63,9 @@ public void TestQubitManager() long qubitsAvailable; - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qab = qm.Borrow(5, exclusion); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 1); Assert.True(qab[0].Id == 0); Assert.True(qab[1].Id == 2); Assert.True(qab[2].Id == 4); @@ -76,9 +76,9 @@ public void TestQubitManager() Assert.True(q6.Id == 9); // Test borrowing of the same qubit again - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb1 = qm.Borrow(1, exclusion); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 0); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 0); Assert.True(qb1[0].Id == 0); qm.Return(qb1[0]); @@ -262,18 +262,18 @@ public void TestQubitManagerTrackingScope() long qubitsAvailable; - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb1 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 1); Assert.True(qb1[0].Id == 0); Assert.True(qb1[1].Id == 5); Assert.True(qb1[2].Id == 6); qm.Return(qb1[0]); qm.Return(qb1[2]); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb2 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 2); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 2); Assert.True(qb2[0].Id == 0); Assert.True(qb2[1].Id == 6); Assert.True(qb2[2].Id == 7); @@ -281,9 +281,9 @@ public void TestQubitManagerTrackingScope() { qm.OnOperationStart(null, qb2); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb3 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 0); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 0); Assert.True(qb3[0].Id == 1); Assert.True(qb3[1].Id == 2); Assert.True(qb3[2].Id == 3); @@ -291,9 +291,9 @@ public void TestQubitManagerTrackingScope() qm.OnOperationEnd(null, QVoid.Instance); } - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb4 = qm.Borrow(1); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 1); Assert.True(qb4[0].Id == 8); qm.OnOperationEnd(null, QVoid.Instance); @@ -321,54 +321,54 @@ public void TestQubitManagerDisabledBorrowing() long qubitsAvailable; - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb1 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 3); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 3); Assert.True(qb1[0].Id == 6); Assert.True(qb1[1].Id == 7); Assert.True(qb1[2].Id == 8); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 11); qm.Return(qb1[0]); qm.Return(qb1[2]); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 13); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb2 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 3); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 3); Assert.True(qb2[0].Id == 8); Assert.True(qb2[1].Id == 6); Assert.True(qb2[2].Id == 9); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 10); { qm.OnOperationStart(null, qb2); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb3 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 3); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 3); Assert.True(qb3[0].Id == 10); Assert.True(qb3[1].Id == 11); Assert.True(qb3[2].Id == 12); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 7); qm.OnOperationEnd(null, QVoid.Instance); } qm.Release(qb2[1]); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 8); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb4 = qm.Borrow(1); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 1); Assert.True(qb4[0].Id == 6); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 7); qm.OnOperationEnd(null, QVoid.Instance); @@ -396,19 +396,19 @@ public void TestQubitManagerGrowth() long qubitsAvailable; - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; IQArray qb1 = qm.Borrow(3); - Assert.True(qubitsAvailable - qm.GetFreeQubitsCount() == 1); + Assert.True(qubitsAvailable - qm.FreeQubitsCount == 1); Assert.True(qb1[0].Id == 0); Assert.True(qb1[1].Id == 5); Assert.True(qb1[2].Id == 6); qm.Return(qb1[0]); qm.Return(qb1[2]); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 1); IQArray qb2 = qm.Borrow(3); // This should grow qubit capacity - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 6); Assert.True(qb2[0].Id == 0); Assert.True(qb2[1].Id == 6); @@ -416,10 +416,10 @@ public void TestQubitManagerGrowth() qm.OnOperationEnd(null, null); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 6); IQArray qa2 = qm.Allocate(4); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 2); Assert.True(qa2.Length == 4); Assert.True(qa2[0].Id == 8); @@ -427,14 +427,14 @@ public void TestQubitManagerGrowth() Assert.True(qa2[2].Id == 10); Assert.True(qa2[3].Id == 11); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 2); qm.Release(qa2[0]); - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 3); IQArray qa3 = qm.Allocate(4); // This should grow qubit capacity - qubitsAvailable = qm.GetFreeQubitsCount(); + qubitsAvailable = qm.FreeQubitsCount; Assert.True(qubitsAvailable == 13); Assert.True(qa3.Length == 4); Assert.True(qa3[0].Id == 8); diff --git a/src/Simulation/Simulators/QuantumProcessor/Borrow.cs b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs index e5700cc8b8d..00010ab101c 100644 --- a/src/Simulation/Simulators/QuantumProcessor/Borrow.cs +++ b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs @@ -16,18 +16,18 @@ public QuantumProcessorDispatcherBorrow(QuantumProcessorDispatcher m) : base(m){ public override Qubit Apply() { - long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedBefore = sim.QubitManager.AllocatedQubitsCount; Qubit qubit = sim.QubitManager.Borrow(); - long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedAfter = sim.QubitManager.AllocatedQubitsCount; sim.QuantumProcessor.OnBorrowQubits(new QArray(qubit), allocatedAfter - allocatedBefore); return qubit; } public override IQArray Apply(long count) { - long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedBefore = sim.QubitManager.AllocatedQubitsCount; IQArray qubits = sim.QubitManager.Borrow(count); - long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedAfter = sim.QubitManager.AllocatedQubitsCount; sim.QuantumProcessor.OnBorrowQubits(qubits, allocatedAfter - allocatedBefore); return qubits; } diff --git a/src/Simulation/Simulators/QuantumProcessor/Return.cs b/src/Simulation/Simulators/QuantumProcessor/Return.cs index a4aa62ada60..14a5f7dc62a 100644 --- a/src/Simulation/Simulators/QuantumProcessor/Return.cs +++ b/src/Simulation/Simulators/QuantumProcessor/Return.cs @@ -16,17 +16,17 @@ public QuantumProcessorDispatcherReturn(QuantumProcessorDispatcher m) : base(m){ public override void Apply(Qubit q) { - long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedBefore = sim.QubitManager.AllocatedQubitsCount; sim.QubitManager.Return(q); - long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedAfter = sim.QubitManager.AllocatedQubitsCount; sim.QuantumProcessor.OnReturnQubits(new QArray(q), allocatedBefore - allocatedAfter); } public override void Apply(IQArray qubits) { - long allocatedBefore = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedBefore = sim.QubitManager.AllocatedQubitsCount; sim.QubitManager.Return(qubits); - long allocatedAfter = sim.QubitManager.GetAllocatedQubitsCount(); + long allocatedAfter = sim.QubitManager.AllocatedQubitsCount; sim.QuantumProcessor.OnReturnQubits(qubits, allocatedBefore - allocatedAfter); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs index a4f7bf96ece..acf8fdf29b5 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QuantumSimulator.cs @@ -200,7 +200,7 @@ public uint[] QubitIds { var ids = new List(); sim_QubitsIds(this.Id, ids.Add); - Debug.Assert(ids.Count == this.QubitManager.GetAllocatedQubitsCount()); + Debug.Assert(ids.Count == this.QubitManager.AllocatedQubitsCount); return ids.ToArray(); } } diff --git a/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs b/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs index ab08a75eee0..f074b6ed8ea 100644 --- a/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs +++ b/src/Simulation/Simulators/QuantumSimulator/StateDumper.cs @@ -177,7 +177,7 @@ public override bool Callback(uint idx, double real, double img) public override bool Dump(IQArray? qubits = null) { var count = qubits == null - ? this.Simulator.QubitManager.GetAllocatedQubitsCount() + ? this.Simulator.QubitManager.AllocatedQubitsCount : qubits.Length; this._maxCharsStateId = ((1 << (int)count) - 1).ToString().Length; diff --git a/src/Simulation/Simulators/ToffoliSimulator/Dump.cs b/src/Simulation/Simulators/ToffoliSimulator/Dump.cs index aec28a147aa..2e97ef268a7 100644 --- a/src/Simulation/Simulators/ToffoliSimulator/Dump.cs +++ b/src/Simulation/Simulators/ToffoliSimulator/Dump.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.IO; using System.Linq; using Microsoft.Quantum.Simulation.Core; @@ -13,7 +12,7 @@ public partial class ToffoliSimulator /// /// Implementation of the DumpMachine operation for the Toffoli simulator. /// - public class DumpMachine : Quantum.Diagnostics.DumpMachine + public class DumpMachine : Diagnostics.DumpMachine { private ToffoliSimulator simulator { get; } @@ -33,7 +32,7 @@ public DumpMachine(ToffoliSimulator m) : base(m) { if (location == null) { throw new ArgumentNullException(nameof(location)); } - var ids = this.simulator.QubitManager.GetAllocatedIds().ToArray(); + var ids = this.simulator.QubitManager.AllocatedIds().ToArray(); var filename = (location is QVoid) ? "" : location.ToString(); this.simulator.DumpState(ids, filename); @@ -44,7 +43,7 @@ public DumpMachine(ToffoliSimulator m) : base(m) /// /// Implementation of the DumpRegister operation for the Toffoli simulator. /// - public class DumpRegister : Quantum.Diagnostics.DumpRegister + public class DumpRegister : Diagnostics.DumpRegister { private ToffoliSimulator simulator { get; } From 8a6a83bfa2a3e07a91e4ab810ea31011f7f54e8d Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Sat, 12 Sep 2020 06:38:13 -0700 Subject: [PATCH 19/20] qubit allocation events --- src/Simulation/Common/SimulatorBase.cs | 41 +++++++++++++------ .../Simulators.Tests/SimulatorBaseTests.cs | 4 +- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index eb086e058b8..4b7d4e25945 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -39,13 +39,20 @@ public abstract class SimulatorBase : Factory, IOperationFacto { public event Action? OnOperationStart = null; public event Action? OnOperationEnd = null; + + public event Action? BeforeAllocateQubits = null; + public event Action>? AfterAllocateQubits = null; + public event Action>? BeforeReleaseQubits = null; + public event Action? AfterReleaseQubits = null; + + public event Action? BeforeBorrowQubits = null; + public event Action>? AfterBorrowQubits = null; + public event Action>? BeforeReturnQubits = null; + public event Action? AfterReturnQubits = null; + public event Action? OnFail = null; - public event Action? OnAllocateQubits = null; - public event Action>? OnReleaseQubits = null; - public event Action? OnBorrowQubits = null; - public event Action>? OnReturnQubits = null; - public event Action? OnLog = null; public event Action>? OnException = null; + public event Action? OnLog = null; protected readonly int randomSeed; protected readonly Lazy randomGenerator; @@ -294,15 +301,17 @@ public Allocate(SimulatorBase m) : base(m) public override Qubit Apply() { + sim.BeforeAllocateQubits?.Invoke(1); Qubit qubit = manager.Allocate(); - sim.OnAllocateQubits?.Invoke(1); + sim.AfterAllocateQubits?.Invoke(new QArray(qubit)); return qubit; } public override IQArray Apply(long count) { + sim.BeforeAllocateQubits?.Invoke(count); IQArray qubits = manager.Allocate(count); - sim.OnAllocateQubits?.Invoke(count); + sim.AfterAllocateQubits?.Invoke(qubits); return qubits; } } @@ -324,14 +333,16 @@ public Release(SimulatorBase m) : base(m) public override void Apply(Qubit q) { - sim.OnReleaseQubits?.Invoke(new QArray(new[] { q })); + sim.BeforeReleaseQubits?.Invoke(new QArray(q)); manager.Release(q); + sim.AfterReleaseQubits?.Invoke(1); } public override void Apply(IQArray qubits) { - sim.OnReleaseQubits?.Invoke(qubits); + sim.BeforeReleaseQubits?.Invoke(qubits); manager.Release(qubits); + sim.AfterReleaseQubits?.Invoke(qubits.Length); } } @@ -352,15 +363,17 @@ public Borrow(SimulatorBase m) : base(m) public override Qubit Apply() { + sim.BeforeBorrowQubits?.Invoke(1); Qubit qubit = manager.Borrow(); - sim.OnBorrowQubits?.Invoke(1); + sim.AfterBorrowQubits?.Invoke(new QArray(qubit)); return qubit; } public override IQArray Apply(long count) { + sim.BeforeBorrowQubits?.Invoke(count); IQArray qubits = manager.Borrow(count); - sim.OnBorrowQubits?.Invoke(count); + sim.AfterBorrowQubits?.Invoke(qubits); return qubits; } } @@ -382,14 +395,16 @@ public Return(SimulatorBase m) : base(m) public override void Apply(Qubit q) { - sim.OnReturnQubits?.Invoke(new QArray(new[] { q })); + sim.BeforeReturnQubits?.Invoke(new QArray(q)); manager.Return(q); + sim.AfterReturnQubits?.Invoke(1); } public override void Apply(IQArray qubits) { - sim.OnReturnQubits?.Invoke(qubits); + sim.BeforeReturnQubits?.Invoke(qubits); manager.Return(qubits); + sim.AfterReturnQubits?.Invoke(qubits.Length); } } diff --git a/src/Simulation/Simulators.Tests/SimulatorBaseTests.cs b/src/Simulation/Simulators.Tests/SimulatorBaseTests.cs index 84c78044fdb..da983d1e352 100644 --- a/src/Simulation/Simulators.Tests/SimulatorBaseTests.cs +++ b/src/Simulation/Simulators.Tests/SimulatorBaseTests.cs @@ -47,12 +47,12 @@ public void SimulatorBuiltInOperations() // are actually called. var calledOnAllocate = false; var calledOnRelease = false; - subject.OnAllocateQubits += count => + subject.BeforeAllocateQubits += count => { output.WriteLine($"Allocate count = {count}"); calledOnAllocate = true; }; - subject.OnReleaseQubits += register => + subject.BeforeReleaseQubits += register => { output.WriteLine($"Release qubits = {register}"); calledOnRelease = true; From 5c47a681657c2d9131bed36cc4bee03542fba6ba Mon Sep 17 00:00:00 2001 From: Bettina Heim Date: Sat, 12 Sep 2020 19:21:11 -0700 Subject: [PATCH 20/20] correct stack handling --- src/Simulation/Common/QubitManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs index c35d2edda98..deec96a147e 100644 --- a/src/Simulation/Common/QubitManager.cs +++ b/src/Simulation/Common/QubitManager.cs @@ -240,7 +240,7 @@ public virtual long QubitsAvailableToBorrowCount(int stackFrame) } var popped = new Stack(); - while (--stackFrame > 0) + while (stackFrame-- > 0) { popped.Push(operationStack.Pop()); }