diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 1dd146c4f22..aba000d7765 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -83,7 +83,7 @@ public Operation(IOperationFactory m) : base(m) { Label = ((ICallable)this).Name, FormattedNonQubitArgs = args.GetNonQubitArgumentsAsString() ?? "", - Targets = args.GetQubits(), + Targets = args.GetQubits() ?? new List(), }; public O Apply(I a) diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index 9054ce12cc2..d61f63050f9 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -44,8 +44,7 @@ public class RuntimeMetadata /// /// /// - /// Currently not used as this is intended for composite operations, - /// such as ApplyToEach. + /// This is used in composite operations, such as ApplyToEach. /// public bool IsComposite { get; set; } @@ -53,7 +52,7 @@ public class RuntimeMetadata /// Group of operations for each classical branch (true and false). /// /// - /// Currently not used as this is intended for classically-controlled operations. + /// This is used in classically-controlled operations. /// public IEnumerable>? Children { get; set; } diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index d710f1c8617..c47650b0b77 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -6,6 +6,7 @@ using System; using System.Collections; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -155,15 +156,13 @@ public static Type[] GetTupleFieldTypes(this Type arg) { var t = o.GetType(); - // If object is a Qubit, ignore it (i.e. return null) - if (o is Qubit) return null; + // If object is a Qubit, QVoid, or array of Qubits, ignore it (i.e. return null) + if (o is Qubit || o is QVoid || o is IEnumerable) return null; - // If object is an IApplyData, recursively extract nested fields - // and stringify them + // If object is an IApplyData, recursively extract arguments if (o is IApplyData data) { - var argsString = data.Value.GetNonQubitArgumentsAsString(); - return argsString.Any() ? argsString : null; + return data.Value.GetNonQubitArgumentsAsString(); } // If object is a string, enclose it in quotations diff --git a/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs index dcb7df85c86..668f7ee5bf5 100644 --- a/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs +++ b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs @@ -2,9 +2,24 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { - + + open Microsoft.Quantum.Intrinsic; + newtype FooUDT = (String, (Qubit, Double)); operation FooUDTOp (foo : FooUDT) : Unit is Ctl + Adj { } + + operation Empty () : Unit is Ctl + Adj { } + + operation HOp (q : Qubit) : Unit { + H(q); + Reset(q); + } + + operation NestedOp () : Unit { + using (q = Qubit()) { + HOp(q); + } + } } diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 5e551565841..629417598b0 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -230,6 +230,29 @@ public void CCNOT() Assert.Equal(op.GetRuntimeMetadata(args), expected); } + [Fact] + public void Swap() + { + var q1 = new FreeQubit(0); + var q2 = new FreeQubit(1); + var op = new QuantumSimulator().Get(); + var args = op.__dataIn((q1, q2)); + var expected = new RuntimeMetadata() + { + Label = "SWAP", + FormattedNonQubitArgs = "", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { q1, q2 }, + }; + + Assert.Equal(op.GetRuntimeMetadata(args), expected); + } + [Fact] public void Ry() { @@ -273,6 +296,28 @@ public void M() Assert.Equal(op.GetRuntimeMetadata(args), expected); } + + [Fact] + public void ResetAll() + { + IQArray targets = new QArray(new[] { new FreeQubit(0) }); + var op = new QuantumSimulator().Get(); + var args = op.__dataIn(targets); + var expected = new RuntimeMetadata() + { + Label = "ResetAll", + FormattedNonQubitArgs = "", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = targets, + }; + + Assert.Equal(op.GetRuntimeMetadata(args), expected); + } } public class MeasurementTests @@ -342,6 +387,50 @@ public void MResetZ() Assert.Equal(op.GetRuntimeMetadata(args), expected); } + + [Fact] + public void EmptyOperation() + { + var measureQubit = new FreeQubit(0); + var op = new QuantumSimulator().Get(); + var args = op.__dataIn(QVoid.Instance); + var expected = new RuntimeMetadata() + { + Label = "Empty", + FormattedNonQubitArgs = "", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { }, + }; + + Assert.Equal(op.GetRuntimeMetadata(args), expected); + } + + [Fact] + public void NestedOperation() + { + var measureQubit = new FreeQubit(0); + var op = new QuantumSimulator().Get(); + var args = op.__dataIn(QVoid.Instance); + var expected = new RuntimeMetadata() + { + Label = "NestedOp", + FormattedNonQubitArgs = "", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { }, + }; + + Assert.Equal(op.GetRuntimeMetadata(args), expected); + } } public class UDTTests diff --git a/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs index 8e025482316..5fa2f260610 100644 --- a/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs +++ b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs @@ -33,6 +33,22 @@ public void BasicTypes() Assert.Equal("\"\"", "".GetNonQubitArgumentsAsString()); } + [Fact] + public void QubitTypes() + { + var q = new FreeQubit(0); + Assert.Null(q.GetNonQubitArgumentsAsString()); + + var qs = new QArray(new[] { new FreeQubit(0) }); + Assert.Null(qs.GetNonQubitArgumentsAsString()); + + qs = new QArray(new[] { new FreeQubit(0), new FreeQubit(1) }); + Assert.Null(qs.GetNonQubitArgumentsAsString()); + + var qtuple = new QTuple(q); + Assert.Null(qtuple.GetNonQubitArgumentsAsString()); + } + [Fact] public void TupleTypes() { @@ -41,6 +57,9 @@ public void TupleTypes() Assert.Equal("(\"foo\", \"bar\", \"\")", ("foo", "bar", "").GetNonQubitArgumentsAsString()); Assert.Equal("(\"foo\", (\"bar\", \"car\"))", ("foo", ("bar", "car")).GetNonQubitArgumentsAsString()); Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", (("foo", new FreeQubit(0)), ("bar", "car")).GetNonQubitArgumentsAsString()); + + var qtuple = new QTuple<(Qubit, string)>((new FreeQubit(0), "foo")); + Assert.Equal("(\"foo\")", qtuple.GetNonQubitArgumentsAsString()); } [Fact] @@ -84,6 +103,22 @@ public void IApplyDataTypes() }; data = new ApplyData<(FreeQubit, string)[]>(arr); Assert.Equal("[(\"foo\"), (\"bar\")]", data.GetNonQubitArgumentsAsString()); + + var qtupleWithString = new QTuple<(Qubit, string)>((new FreeQubit(0), "foo")); + data = new ApplyData>(qtupleWithString); + Assert.Equal("(\"foo\")", data.GetNonQubitArgumentsAsString()); + + var q = new FreeQubit(0); + data = new ApplyData(q); + Assert.Null(data.GetNonQubitArgumentsAsString()); + + var qs = new QArray(new[] { new FreeQubit(0), new FreeQubit(1) }); + data = new ApplyData>(qs); + Assert.Null(data.GetNonQubitArgumentsAsString()); + + var qtuple = new QTuple(q); + data = new ApplyData>(qtuple); + Assert.Null(data.GetNonQubitArgumentsAsString()); } } }