Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit 08ae4a4

Browse files
authored
Fix stack overflow bug for Qubit array types on RuntimeMetadata (#312)
1 parent b1af02d commit 08ae4a4

File tree

6 files changed

+148
-11
lines changed

6 files changed

+148
-11
lines changed

src/Simulation/Core/Operations/Operation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public Operation(IOperationFactory m) : base(m)
8383
{
8484
Label = ((ICallable)this).Name,
8585
FormattedNonQubitArgs = args.GetNonQubitArgumentsAsString() ?? "",
86-
Targets = args.GetQubits(),
86+
Targets = args.GetQubits() ?? new List<Qubit>(),
8787
};
8888

8989
public O Apply(I a)

src/Simulation/Core/RuntimeMetadata.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,15 @@ public class RuntimeMetadata
4444
/// </summary>
4545
/// </summary>
4646
/// <remarks>
47-
/// Currently not used as this is intended for composite operations,
48-
/// such as <c>ApplyToEach</c>.
47+
/// This is used in composite operations, such as <c>ApplyToEach</c>.
4948
/// </remarks>
5049
public bool IsComposite { get; set; }
5150

5251
/// <summary>
5352
/// Group of operations for each classical branch (<c>true</c> and <c>false</c>).
5453
/// </summary>
5554
/// <remarks>
56-
/// Currently not used as this is intended for classically-controlled operations.
55+
/// This is used in classically-controlled operations.
5756
/// </remarks>
5857
public IEnumerable<IEnumerable<RuntimeMetadata>>? Children { get; set; }
5958

src/Simulation/Core/TypeExtensions.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System;
77
using System.Collections;
88
using System.Collections.Concurrent;
9+
using System.Collections.Generic;
910
using System.Diagnostics;
1011
using System.Linq;
1112

@@ -155,15 +156,13 @@ public static Type[] GetTupleFieldTypes(this Type arg)
155156
{
156157
var t = o.GetType();
157158

158-
// If object is a Qubit, ignore it (i.e. return null)
159-
if (o is Qubit) return null;
159+
// If object is a Qubit, QVoid, or array of Qubits, ignore it (i.e. return null)
160+
if (o is Qubit || o is QVoid || o is IEnumerable<Qubit>) return null;
160161

161-
// If object is an IApplyData, recursively extract nested fields
162-
// and stringify them
162+
// If object is an IApplyData, recursively extract arguments
163163
if (o is IApplyData data)
164164
{
165-
var argsString = data.Value.GetNonQubitArgumentsAsString();
166-
return argsString.Any() ? argsString : null;
165+
return data.Value.GetNonQubitArgumentsAsString();
167166
}
168167

169168
// If object is a string, enclose it in quotations

src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,24 @@
22
// Licensed under the MIT License.
33

44
namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits {
5-
5+
6+
open Microsoft.Quantum.Intrinsic;
7+
68
newtype FooUDT = (String, (Qubit, Double));
79

810
operation FooUDTOp (foo : FooUDT) : Unit is Ctl + Adj { }
11+
12+
operation Empty () : Unit is Ctl + Adj { }
13+
14+
operation HOp (q : Qubit) : Unit {
15+
H(q);
16+
Reset(q);
17+
}
18+
19+
operation NestedOp () : Unit {
20+
using (q = Qubit()) {
21+
HOp(q);
22+
}
23+
}
924

1025
}

src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,29 @@ public void CCNOT()
230230
Assert.Equal(op.GetRuntimeMetadata(args), expected);
231231
}
232232

233+
[Fact]
234+
public void Swap()
235+
{
236+
var q1 = new FreeQubit(0);
237+
var q2 = new FreeQubit(1);
238+
var op = new QuantumSimulator().Get<Intrinsic.SWAP>();
239+
var args = op.__dataIn((q1, q2));
240+
var expected = new RuntimeMetadata()
241+
{
242+
Label = "SWAP",
243+
FormattedNonQubitArgs = "",
244+
IsAdjoint = false,
245+
IsControlled = false,
246+
IsMeasurement = false,
247+
IsComposite = false,
248+
Children = null,
249+
Controls = new List<Qubit>() { },
250+
Targets = new List<Qubit>() { q1, q2 },
251+
};
252+
253+
Assert.Equal(op.GetRuntimeMetadata(args), expected);
254+
}
255+
233256
[Fact]
234257
public void Ry()
235258
{
@@ -273,6 +296,28 @@ public void M()
273296

274297
Assert.Equal(op.GetRuntimeMetadata(args), expected);
275298
}
299+
300+
[Fact]
301+
public void ResetAll()
302+
{
303+
IQArray<Qubit> targets = new QArray<Qubit>(new[] { new FreeQubit(0) });
304+
var op = new QuantumSimulator().Get<Intrinsic.ResetAll>();
305+
var args = op.__dataIn(targets);
306+
var expected = new RuntimeMetadata()
307+
{
308+
Label = "ResetAll",
309+
FormattedNonQubitArgs = "",
310+
IsAdjoint = false,
311+
IsControlled = false,
312+
IsMeasurement = false,
313+
IsComposite = false,
314+
Children = null,
315+
Controls = new List<Qubit>() { },
316+
Targets = targets,
317+
};
318+
319+
Assert.Equal(op.GetRuntimeMetadata(args), expected);
320+
}
276321
}
277322

278323
public class MeasurementTests
@@ -342,6 +387,50 @@ public void MResetZ()
342387

343388
Assert.Equal(op.GetRuntimeMetadata(args), expected);
344389
}
390+
391+
[Fact]
392+
public void EmptyOperation()
393+
{
394+
var measureQubit = new FreeQubit(0);
395+
var op = new QuantumSimulator().Get<Circuits.Empty>();
396+
var args = op.__dataIn(QVoid.Instance);
397+
var expected = new RuntimeMetadata()
398+
{
399+
Label = "Empty",
400+
FormattedNonQubitArgs = "",
401+
IsAdjoint = false,
402+
IsControlled = false,
403+
IsMeasurement = false,
404+
IsComposite = false,
405+
Children = null,
406+
Controls = new List<Qubit>() { },
407+
Targets = new List<Qubit>() { },
408+
};
409+
410+
Assert.Equal(op.GetRuntimeMetadata(args), expected);
411+
}
412+
413+
[Fact]
414+
public void NestedOperation()
415+
{
416+
var measureQubit = new FreeQubit(0);
417+
var op = new QuantumSimulator().Get<Circuits.NestedOp>();
418+
var args = op.__dataIn(QVoid.Instance);
419+
var expected = new RuntimeMetadata()
420+
{
421+
Label = "NestedOp",
422+
FormattedNonQubitArgs = "",
423+
IsAdjoint = false,
424+
IsControlled = false,
425+
IsMeasurement = false,
426+
IsComposite = false,
427+
Children = null,
428+
Controls = new List<Qubit>() { },
429+
Targets = new List<Qubit>() { },
430+
};
431+
432+
Assert.Equal(op.GetRuntimeMetadata(args), expected);
433+
}
345434
}
346435

347436
public class UDTTests

src/Simulation/Simulators.Tests/TypeExtensionsTest.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ public void BasicTypes()
3333
Assert.Equal("\"\"", "".GetNonQubitArgumentsAsString());
3434
}
3535

36+
[Fact]
37+
public void QubitTypes()
38+
{
39+
var q = new FreeQubit(0);
40+
Assert.Null(q.GetNonQubitArgumentsAsString());
41+
42+
var qs = new QArray<Qubit>(new[] { new FreeQubit(0) });
43+
Assert.Null(qs.GetNonQubitArgumentsAsString());
44+
45+
qs = new QArray<Qubit>(new[] { new FreeQubit(0), new FreeQubit(1) });
46+
Assert.Null(qs.GetNonQubitArgumentsAsString());
47+
48+
var qtuple = new QTuple<Qubit>(q);
49+
Assert.Null(qtuple.GetNonQubitArgumentsAsString());
50+
}
51+
3652
[Fact]
3753
public void TupleTypes()
3854
{
@@ -41,6 +57,9 @@ public void TupleTypes()
4157
Assert.Equal("(\"foo\", \"bar\", \"\")", ("foo", "bar", "").GetNonQubitArgumentsAsString());
4258
Assert.Equal("(\"foo\", (\"bar\", \"car\"))", ("foo", ("bar", "car")).GetNonQubitArgumentsAsString());
4359
Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", (("foo", new FreeQubit(0)), ("bar", "car")).GetNonQubitArgumentsAsString());
60+
61+
var qtuple = new QTuple<(Qubit, string)>((new FreeQubit(0), "foo"));
62+
Assert.Equal("(\"foo\")", qtuple.GetNonQubitArgumentsAsString());
4463
}
4564

4665
[Fact]
@@ -84,6 +103,22 @@ public void IApplyDataTypes()
84103
};
85104
data = new ApplyData<(FreeQubit, string)[]>(arr);
86105
Assert.Equal("[(\"foo\"), (\"bar\")]", data.GetNonQubitArgumentsAsString());
106+
107+
var qtupleWithString = new QTuple<(Qubit, string)>((new FreeQubit(0), "foo"));
108+
data = new ApplyData<QTuple<(Qubit, string)>>(qtupleWithString);
109+
Assert.Equal("(\"foo\")", data.GetNonQubitArgumentsAsString());
110+
111+
var q = new FreeQubit(0);
112+
data = new ApplyData<Qubit>(q);
113+
Assert.Null(data.GetNonQubitArgumentsAsString());
114+
115+
var qs = new QArray<Qubit>(new[] { new FreeQubit(0), new FreeQubit(1) });
116+
data = new ApplyData<IQArray<Qubit>>(qs);
117+
Assert.Null(data.GetNonQubitArgumentsAsString());
118+
119+
var qtuple = new QTuple<Qubit>(q);
120+
data = new ApplyData<QTuple<Qubit>>(qtuple);
121+
Assert.Null(data.GetNonQubitArgumentsAsString());
87122
}
88123
}
89124
}

0 commit comments

Comments
 (0)