diff --git a/src/Simulation/Common/QubitManager.cs b/src/Simulation/Common/QubitManager.cs
index bd19bdad338..a70651f5059 100644
--- a/src/Simulation/Common/QubitManager.cs
+++ b/src/Simulation/Common/QubitManager.cs
@@ -5,6 +5,7 @@
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;
@@ -25,11 +26,13 @@ public class QubitManager
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.
// Options
bool MayExtendCapacity;
+ bool EncourageReuse;
public bool DisableBorrowing { get; }
const long MaxQubitCapacity = long.MaxValue - 3;
@@ -49,9 +52,14 @@ public class QubitManager
///
/// Creates and initializes QubitManager that can handle up to numQubits qubits
///
- public QubitManager(long qubitCapacity, bool mayExtendCapacity = false, bool disableBorrowing = false)
+ public QubitManager(
+ long qubitCapacity,
+ bool mayExtendCapacity = false,
+ bool disableBorrowing = false,
+ bool encourageReuse = true)
{
MayExtendCapacity = mayExtendCapacity;
+ EncourageReuse = encourageReuse;
DisableBorrowing = disableBorrowing;
if (qubitCapacity <= 0) { qubitCapacity = MinQubitCapacity; }
@@ -65,6 +73,7 @@ public QubitManager(long qubitCapacity, bool mayExtendCapacity = false, bool dis
Debug.Assert(this.qubits[NumQubits - 1] == None);
free = 0;
+ freeTail = NumQubits - 1;
numAllocatedQubits = 0;
numDisabledQubits = 0;
}
@@ -121,6 +130,7 @@ private void ExtendQubitArray()
if (free == oldNone)
{
free = oldNumQubits;
+ freeTail = NumQubits - 1;
} else
{
Debug.Assert(false, "Why do we extend an array, when we still have available slots?");
@@ -300,8 +310,29 @@ protected virtual void ReleaseOneQubit(Qubit qubit, bool usedOnlyForBorrowing)
{
throw new ArgumentException("Attempt to free qubit that has not been allocated.");
}
- qubits[qubit.Id] = free;
- free = qubit.Id;
+ 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 (qubits[freeTail] != None)
+ {
+ // 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);
diff --git a/src/Simulation/Common/QubitManagerTrackingScope.cs b/src/Simulation/Common/QubitManagerTrackingScope.cs
index 23f654439de..a166f98bfa0 100644
--- a/src/Simulation/Common/QubitManagerTrackingScope.cs
+++ b/src/Simulation/Common/QubitManagerTrackingScope.cs
@@ -44,8 +44,12 @@ public List Locals
private 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)
- : base(qubitCapacity, mayExtendCapacity, disableBorrowing)
+ public QubitManagerTrackingScope(
+ long qubitCapacity,
+ bool mayExtendCapacity = false,
+ bool disableBorrowing = false,
+ bool encourageReuse = true)
+ : base(qubitCapacity, mayExtendCapacity, disableBorrowing, encourageReuse)
{
if (!DisableBorrowing)
{
diff --git a/src/Simulation/Simulators.Tests/QubitManagerTests.cs b/src/Simulation/Simulators.Tests/QubitManagerTests.cs
index a5f2123d0f2..8ee972883a8 100644
--- a/src/Simulation/Simulators.Tests/QubitManagerTests.cs
+++ b/src/Simulation/Simulators.Tests/QubitManagerTests.cs
@@ -152,6 +152,91 @@ public void TestQubitManager()
}
}
+ ///
+ /// Test for QubitManager.
+ ///
+ [Fact]
+ public void TestQubitManagerDiscouragingReuse()
+ {
+ { // BLOCK testing mayExtendCapacity:false
+ QubitManager qm = new QubitManager(10, mayExtendCapacity: false, disableBorrowing: false, encourageReuse: false);
+
+ // Test allocation of single qubit
+ Qubit q1 = qm.Allocate();
+ Assert.True(q1.Id == 0);
+
+ // Test allocation of multiple qubits
+ IQArray qa1 = qm.Allocate(4);
+ Assert.True(qa1.Length == 4);
+ Assert.True(qa1[0].Id == 1);
+ Assert.True(qa1[1].Id == 2);
+ Assert.True(qa1[2].Id == 3);
+ Assert.True(qa1[3].Id == 4);
+
+ // Test reuse of deallocated qubits
+ qm.Release(qa1[1]);
+
+ Qubit q2 = qm.Allocate();
+ Assert.True(q2.Id == 5);
+
+ IQArray qa2 = qm.Allocate(3);
+ Assert.True(qa2.Length == 3);
+ Assert.True(qa2[0].Id == 6);
+ Assert.True(qa2[1].Id == 7);
+ Assert.True(qa2[2].Id == 8);
+
+ qm.Release(qa2);
+
+ Qubit q3 = qm.Allocate();
+ Assert.True(q3.Id == 9);
+
+ Qubit q4 = qm.Allocate();
+ Assert.True(q4.Id == 2);
+
+ Qubit q5 = qm.Allocate();
+ Assert.True(q5.Id == 8);
+ }
+
+ { // BLOCK testing mayExtendCapacity:true
+ QubitManager qm = new QubitManager(10, mayExtendCapacity: true, disableBorrowing: false, encourageReuse: false);
+
+ // Test allocation of single qubit
+ Qubit q1 = qm.Allocate();
+ Assert.True(q1.Id == 0);
+
+ // Test allocation of multiple qubits
+ IQArray qa1 = qm.Allocate(4);
+ Assert.True(qa1.Length == 4);
+ Assert.True(qa1[0].Id == 1);
+ Assert.True(qa1[1].Id == 2);
+ Assert.True(qa1[2].Id == 3);
+ Assert.True(qa1[3].Id == 4);
+
+ // Test reuse of deallocated qubits
+ qm.Release(qa1[1]);
+
+ Qubit q2 = qm.Allocate();
+ Assert.True(q2.Id == 5);
+
+ IQArray qa2 = qm.Allocate(3);
+ Assert.True(qa2.Length == 3);
+ Assert.True(qa2[0].Id == 6);
+ Assert.True(qa2[1].Id == 7);
+ Assert.True(qa2[2].Id == 8);
+
+ qm.Release(qa2);
+
+ Qubit q3 = qm.Allocate();
+ Assert.True(q3.Id == 9);
+
+ Qubit q4 = qm.Allocate();
+ Assert.True(q4.Id == 10);
+
+ Qubit q5 = qm.Allocate();
+ Assert.True(q5.Id == 11);
+ }
+ }
+
///
/// Test for QubitManagerTrackingScope.
///