From a7746507b550a0c6d08145d61bd66b5ac2aec39b Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Wed, 8 Jul 2020 15:14:55 -0400 Subject: [PATCH 01/11] Implement GetRuntimeMetadata methods --- src/Simulation/Core/AbstractCallable.cs | 5 + .../Core/Generics/GenericCallable.cs | 2 + src/Simulation/Core/Operations/Adjoint.cs | 7 + src/Simulation/Core/Operations/Controlled.cs | 18 ++ src/Simulation/Core/Operations/Operation.cs | 9 +- .../Core/Operations/OperationPartial.cs | 3 + src/Simulation/Core/RuntimeMetadata.cs | 60 ++++++ src/Simulation/Core/TypeExtensions.cs | 36 +++- src/Simulation/Core/Udts/UDTPartial.cs | 2 + src/Simulation/QsharpCore/Intrinsic.cs | 94 +++++++++ src/Simulation/QsharpCore/Measurement.cs | 59 ++++++ .../Simulators.Tests/RuntimeMetadataTests.cs | 180 ++++++++++++++++++ 12 files changed, 473 insertions(+), 2 deletions(-) create mode 100644 src/Simulation/Core/RuntimeMetadata.cs create mode 100644 src/Simulation/QsharpCore/Intrinsic.cs create mode 100644 src/Simulation/QsharpCore/Measurement.cs create mode 100644 src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs diff --git a/src/Simulation/Core/AbstractCallable.cs b/src/Simulation/Core/AbstractCallable.cs index dd11d22d7cd..93fd405ef46 100644 --- a/src/Simulation/Core/AbstractCallable.cs +++ b/src/Simulation/Core/AbstractCallable.cs @@ -29,6 +29,11 @@ public AbstractCallable(IOperationFactory m) /// public abstract void Init(); + /// + /// Retrieves the runtime metadata of the Operation. + /// + public virtual RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + object IApplyData.Value => null; IEnumerable IApplyData.Qubits => null; diff --git a/src/Simulation/Core/Generics/GenericCallable.cs b/src/Simulation/Core/Generics/GenericCallable.cs index e0668b3723f..3d34ff2bc6f 100644 --- a/src/Simulation/Core/Generics/GenericCallable.cs +++ b/src/Simulation/Core/Generics/GenericCallable.cs @@ -24,6 +24,8 @@ public partial interface ICallable : IApplyData O Apply(object args); ICallable Partial(object partialTuple); + + RuntimeMetadata GetRuntimeMetadata(IApplyData args); } /// diff --git a/src/Simulation/Core/Operations/Adjoint.cs b/src/Simulation/Core/Operations/Adjoint.cs index 6db9f4a9f81..f3a3167c0f7 100644 --- a/src/Simulation/Core/Operations/Adjoint.cs +++ b/src/Simulation/Core/Operations/Adjoint.cs @@ -72,6 +72,13 @@ public override void Init() { } public override IApplyData __dataOut(QVoid data) => data; + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var baseMetadata = this.BaseOp.GetRuntimeMetadata(args); + baseMetadata.IsAdjoint = true; + return baseMetadata; + } + public override string ToString() => $"(Adjoint {BaseOp?.ToString() ?? "" })"; public override string __qsharpType() => this.BaseOp?.__qsharpType(); diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index 8df3a8eb579..9d25ee3e10a 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; namespace Microsoft.Quantum.Simulation.Core @@ -110,6 +111,23 @@ public override void Init() { } public override IApplyData __dataOut(QVoid data) => data; + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + if (args.Value is ValueTuple, I> ctrlArgs) + { + var (controls, baseArgs) = ctrlArgs; + var baseMetadata = this.BaseOp.GetRuntimeMetadata(this.BaseOp.__dataIn(baseArgs)); + baseMetadata.IsControlled = true; + baseMetadata.Controls = controls.Concat(baseMetadata.Controls); + return baseMetadata; + } + else + { + Console.WriteLine($"Failed to retrieve control bits for {this.ToString()}."); + return null; + } + } + public override string ToString() => $"(Controlled {BaseOp?.ToString() ?? "" })"; public override string __qsharpType() => GenericControlled.AddControlQubitsToSignature(this.BaseOp?.__qsharpType()); diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index e81248f2528..967e4c06796 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; @@ -75,6 +75,13 @@ public Operation(IOperationFactory m) : base(m) [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ControlledOperation Controlled => _controlled.Value; + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => + new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + Args = args.Value.GetType().ArgsToString(args.Value), + Targets = args.GetQubits(), + }; public O Apply(I a) { diff --git a/src/Simulation/Core/Operations/OperationPartial.cs b/src/Simulation/Core/Operations/OperationPartial.cs index 12e03f01913..fe77dd67c3a 100644 --- a/src/Simulation/Core/Operations/OperationPartial.cs +++ b/src/Simulation/Core/Operations/OperationPartial.cs @@ -141,6 +141,9 @@ ICallable ICallable.Partial(Func mapper) IUnitary IUnitary

.Partial(Func mapper) => new OperationPartial(this, mapper); + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => + this.BaseOp.GetRuntimeMetadata(args); + public override string ToString() => $"{this.BaseOp}{{_}}"; public override string __qsharpType() { diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs new file mode 100644 index 00000000000..655cbe99281 --- /dev/null +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable enable + +using System.Collections.Generic; + +namespace Microsoft.Quantum.Simulation.Core +{ + public class RuntimeMetadata + { + ///

+ /// Label of gate. + /// + public string Label { get; set; } = ""; + + /// + /// Non-qubit arguments provided to gate. + /// + public string? Args { get; set; } + + /// + /// True if operation is an adjoint operation. + /// + public bool IsAdjoint { get; set; } + + /// + /// True if operation is a controlled operation. + /// + public bool IsControlled { get; set; } + + /// + /// True if operation is a measurement operation. + /// + public bool IsMeasurement { get; set; } + + /// + /// True if operation is composed of multiple operations. + /// + public bool IsComposite { get; set; } + + /// + /// Group of operations for each classical branch. + /// + /// + /// Currently not used as this is intended for classically-controlled operations. + /// + public IEnumerable>? Children { get; set; } + + /// + /// List of control registers. + /// + public IEnumerable Controls { get; set; } = new List(); + + /// + /// List of target registers. + /// + public IEnumerable Targets { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index 94bc5ebabf6..ea887e59c32 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -144,6 +146,38 @@ public static Type[] GetTupleFieldTypes(this Type arg) } } + /// + /// Given a and its arguments, format its non-qubit arguments into a string. + /// Returns null if no arguments found. + /// + public static string? ArgsToString(this Type t, object args) + { + var argsStrings = t.GetFields() + .Select(f => + { + var argString = null as string; + + // If field is a tuple, recursively extract its inner arguments and format as a tuple string. + if (f.FieldType.IsTuple()) + { + var nestedArgs = f.GetValue(args); + if (nestedArgs != null) argString = f.FieldType.ArgsToString(nestedArgs); + } + // Add field as an argument if it is not a Qubit type + else if (!f.FieldType.IsQubitsContainer()) + { + argString = f.GetValue(args)?.ToString(); + } + + return argString; + }) + .WhereNotNull(); + + return argsStrings.Any() + ? $"({string.Join(",", argsStrings)})" + : null; + } + private static ConcurrentDictionary _normalTypesCache = new ConcurrentDictionary(); /// @@ -259,7 +293,7 @@ public static string OperationVariants(this Type t, object op) return OperationVariants(generic.OperationType, op); } - return OperationVariants(t.BaseType, op); + return OperationVariants(t.BaseType, op); } public static bool TryQSharpOperationType(Type t, out string typeName) diff --git a/src/Simulation/Core/Udts/UDTPartial.cs b/src/Simulation/Core/Udts/UDTPartial.cs index 8d586d4ee80..3b4fccd1b07 100644 --- a/src/Simulation/Core/Udts/UDTPartial.cs +++ b/src/Simulation/Core/Udts/UDTPartial.cs @@ -62,6 +62,8 @@ public ICallable Partial(object partialTuple) return (ICallable)Activator.CreateInstance(partialType, new object[] { this, partialTuple }); } + public RuntimeMetadata GetRuntimeMetadata(IApplyData args) => throw new NotImplementedException(); + internal class DebuggerProxy { private readonly UDTPartial u; diff --git a/src/Simulation/QsharpCore/Intrinsic.cs b/src/Simulation/QsharpCore/Intrinsic.cs new file mode 100644 index 00000000000..4e3f3903372 --- /dev/null +++ b/src/Simulation/QsharpCore/Intrinsic.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Intrinsic +{ + public partial class CNOT + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var controls = new List(); + var targets = new List(); + + switch (args.Value) + { + case ValueTuple cnotArgs: + var (ctrl, target) = cnotArgs; + controls.Add(ctrl); + targets.Add(target); + break; + default: + Console.WriteLine($"Failed to retrieve arguments of type {args.Value.GetType()} for CNOT."); + break; + } + + return new RuntimeMetadata() + { + Label = "X", + IsControlled = true, + Controls = controls, + Targets = targets, + }; + } + } + + public partial class CCNOT + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var controls = new List(); + var targets = new List(); + + switch (args.Value) + { + case ValueTuple ccnotArgs: + var (ctrl1, ctrl2, target) = ccnotArgs; + controls.Add(ctrl1); + controls.Add(ctrl2); + targets.Add(target); + break; + default: + Console.WriteLine("Failed to retrieve arguments for CNOT."); + break; + } + return new RuntimeMetadata() + { + Label = "X", + IsControlled = true, + Controls = controls, + Targets = targets, + }; + } + } + + public partial class M + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var targets = new List(); + var target = args.Value as Qubit; + if (target != null) targets.Add(target); + + return new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + IsMeasurement = true, + Targets = targets, + }; + } + } + + public partial class Reset + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + } + + public partial class ResetAll + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + } +} diff --git a/src/Simulation/QsharpCore/Measurement.cs b/src/Simulation/QsharpCore/Measurement.cs new file mode 100644 index 00000000000..7061ba0041c --- /dev/null +++ b/src/Simulation/QsharpCore/Measurement.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Measurement +{ + public partial class MResetX + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var targets = new List(); + var target = args.Value as Qubit; + if (target != null) targets.Add(target); + + return new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + IsMeasurement = true, + Targets = targets, + }; + } + } + + public partial class MResetY + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var targets = new List(); + var target = args.Value as Qubit; + if (target != null) targets.Add(target); + + return new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + IsMeasurement = true, + Targets = targets, + }; + } + } + + public partial class MResetZ + { + public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + { + var targets = new List(); + var target = args.Value as Qubit; + if (target != null) targets.Add(target); + + return new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + IsMeasurement = true, + Targets = targets, + }; + } + } +} diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs new file mode 100644 index 00000000000..7267d1e8904 --- /dev/null +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace Microsoft.Quantum.Simulation.Simulators.Tests +{ + public static class IntrinsicTestsExtensions + { + // Look into better ways of checking equality (i.e. GetType().GetProperties()) + public static bool IsEqual(this RuntimeMetadata self, RuntimeMetadata to) => + self.Label == to.Label && self.Args == to.Args && self.IsAdjoint == to.IsAdjoint && + self.IsControlled == to.IsControlled && self.IsMeasurement == to.IsMeasurement && + self.IsComposite == to.IsComposite && + self.Controls.SequenceEqual(to.Controls) && self.Targets.SequenceEqual(to.Targets); + } + + public class IntrinsicTests + { + [Fact] + public void CNOT() + { + var control = new FreeQubit(1); + var target = new FreeQubit(0); + var op = new Microsoft.Quantum.Intrinsic.CNOT(new TrivialSimulator()); + var args = op.__dataIn((control, target)); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { control }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void CCNOT() + { + var control1 = new FreeQubit(0); + var control2 = new FreeQubit(2); + var target = new FreeQubit(1); + var op = new Microsoft.Quantum.Intrinsic.CCNOT(new TrivialSimulator()); + var args = op.__dataIn((control1, control2, target)); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { control1, control2 }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void M() + { + var measureQubit = new FreeQubit(0); + var op = new Microsoft.Quantum.Intrinsic.M(new TrivialSimulator()); + var args = op.__dataIn(measureQubit); + var expected = new RuntimeMetadata() + { + Label = "M", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = true, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { measureQubit }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void Reset() + { + var target = new FreeQubit(0); + var op = new Microsoft.Quantum.Intrinsic.Reset(new TrivialSimulator()); + var args = op.__dataIn(target); + Assert.Null(op.GetRuntimeMetadata(args)); + } + + [Fact] + public void ResetAll() + { + var targets = QArray.Create(3); + var op = new Microsoft.Quantum.Intrinsic.ResetAll(new TrivialSimulator()); + var args = op.__dataIn(targets); + Assert.Null(op.GetRuntimeMetadata(args)); + } + } + + public class MeasurementTests + { + [Fact] + public void MResetX() + { + var measureQubit = new FreeQubit(0); + var op = new Microsoft.Quantum.Measurement.MResetX(new TrivialSimulator()); + var args = op.__dataIn(measureQubit); + var expected = new RuntimeMetadata() + { + Label = "MResetX", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = true, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { measureQubit }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void MResetY() + { + var measureQubit = new FreeQubit(0); + var op = new Microsoft.Quantum.Measurement.MResetY(new TrivialSimulator()); + var args = op.__dataIn(measureQubit); + var expected = new RuntimeMetadata() + { + Label = "MResetY", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = true, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { measureQubit }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void MResetZ() + { + var measureQubit = new FreeQubit(0); + var op = new Microsoft.Quantum.Measurement.MResetZ(new TrivialSimulator()); + var args = op.__dataIn(measureQubit); + var expected = new RuntimeMetadata() + { + Label = "MResetZ", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = true, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { measureQubit }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + } +} From 2576463a56bc8d53f899ee1a983043e1bb3b155b Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Thu, 9 Jul 2020 17:30:27 -0400 Subject: [PATCH 02/11] Improve error messages --- src/Simulation/Core/Operations/Controlled.cs | 2 +- src/Simulation/QsharpCore/Intrinsic.cs | 86 +++++++++----------- 2 files changed, 40 insertions(+), 48 deletions(-) diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index 9d25ee3e10a..ba4630350b4 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -123,7 +123,7 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) } else { - Console.WriteLine($"Failed to retrieve control bits for {this.ToString()}."); + Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); return null; } } diff --git a/src/Simulation/QsharpCore/Intrinsic.cs b/src/Simulation/QsharpCore/Intrinsic.cs index 4e3f3903372..17813be78e8 100644 --- a/src/Simulation/QsharpCore/Intrinsic.cs +++ b/src/Simulation/QsharpCore/Intrinsic.cs @@ -11,28 +11,22 @@ public partial class CNOT { public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) { - var controls = new List(); - var targets = new List(); - - switch (args.Value) + if (args.Value is ValueTuple cnotArgs) { - case ValueTuple cnotArgs: - var (ctrl, target) = cnotArgs; - controls.Add(ctrl); - targets.Add(target); - break; - default: - Console.WriteLine($"Failed to retrieve arguments of type {args.Value.GetType()} for CNOT."); - break; + var (ctrl, target) = cnotArgs; + return new RuntimeMetadata() + { + Label = "X", + IsControlled = true, + Controls = new List() { ctrl }, + Targets = new List() { target }, + }; } - - return new RuntimeMetadata() + else { - Label = "X", - IsControlled = true, - Controls = controls, - Targets = targets, - }; + Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); + return null; + } } } @@ -40,28 +34,22 @@ public partial class CCNOT { public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) { - var controls = new List(); - var targets = new List(); - - switch (args.Value) + if (args.Value is ValueTuple ccnotArgs) { - case ValueTuple ccnotArgs: - var (ctrl1, ctrl2, target) = ccnotArgs; - controls.Add(ctrl1); - controls.Add(ctrl2); - targets.Add(target); - break; - default: - Console.WriteLine("Failed to retrieve arguments for CNOT."); - break; + var (ctrl1, ctrl2, target) = ccnotArgs; + return new RuntimeMetadata() + { + Label = "X", + IsControlled = true, + Controls = new List() { ctrl1, ctrl2 }, + Targets = new List() { target }, + }; } - return new RuntimeMetadata() + else { - Label = "X", - IsControlled = true, - Controls = controls, - Targets = targets, - }; + Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); + return null; + } } } @@ -69,16 +57,20 @@ public partial class M { public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) { - var targets = new List(); - var target = args.Value as Qubit; - if (target != null) targets.Add(target); - - return new RuntimeMetadata() + if (args.Value is Qubit target) + { + return new RuntimeMetadata() + { + Label = ((ICallable)this).Name, + IsMeasurement = true, + Targets = new List() { target }, + }; + } + else { - Label = ((ICallable)this).Name, - IsMeasurement = true, - Targets = targets, - }; + Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); + return null; + } } } From 936f44e14b13bee677dfd72281ec83528e92ff51 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Fri, 10 Jul 2020 11:32:27 -0400 Subject: [PATCH 03/11] Add nullable --- src/Simulation/Core/AbstractCallable.cs | 7 +++++-- src/Simulation/Core/Generics/GenericCallable.cs | 4 +++- src/Simulation/Core/Operations/Adjoint.cs | 6 +++++- src/Simulation/Core/Operations/Controlled.cs | 6 +++++- src/Simulation/Core/Operations/Operation.cs | 7 +++++-- .../Core/Operations/OperationPartial.cs | 5 ++++- src/Simulation/Core/Udts/UDTPartial.cs | 5 ++++- src/Simulation/QsharpCore/Intrinsic.cs | 17 ++++++++++++----- src/Simulation/QsharpCore/Measurement.cs | 11 ++++++++--- 9 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/Simulation/Core/AbstractCallable.cs b/src/Simulation/Core/AbstractCallable.cs index 93fd405ef46..0da7ceb8d1f 100644 --- a/src/Simulation/Core/AbstractCallable.cs +++ b/src/Simulation/Core/AbstractCallable.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System.Collections.Generic; namespace Microsoft.Quantum.Simulation.Core @@ -30,9 +32,10 @@ public AbstractCallable(IOperationFactory m) public abstract void Init(); /// - /// Retrieves the runtime metadata of the Operation. + /// Retrieves the runtime metadata of the Operation. If the Operation has no associated + /// runtime metadata, return null. /// - public virtual RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + public virtual RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; object IApplyData.Value => null; diff --git a/src/Simulation/Core/Generics/GenericCallable.cs b/src/Simulation/Core/Generics/GenericCallable.cs index 3d34ff2bc6f..cdd4ac3fce4 100644 --- a/src/Simulation/Core/Generics/GenericCallable.cs +++ b/src/Simulation/Core/Generics/GenericCallable.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -25,7 +27,7 @@ public partial interface ICallable : IApplyData ICallable Partial(object partialTuple); - RuntimeMetadata GetRuntimeMetadata(IApplyData args); + RuntimeMetadata? GetRuntimeMetadata(IApplyData args); } /// diff --git a/src/Simulation/Core/Operations/Adjoint.cs b/src/Simulation/Core/Operations/Adjoint.cs index f3a3167c0f7..d64e8cf4ef7 100644 --- a/src/Simulation/Core/Operations/Adjoint.cs +++ b/src/Simulation/Core/Operations/Adjoint.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -72,9 +74,11 @@ public override void Init() { } public override IApplyData __dataOut(QVoid data) => data; - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { var baseMetadata = this.BaseOp.GetRuntimeMetadata(args); + if (baseMetadata == null) return null; baseMetadata.IsAdjoint = true; return baseMetadata; } diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index ba4630350b4..89fc39184a1 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -111,12 +113,14 @@ public override void Init() { } public override IApplyData __dataOut(QVoid data) => data; - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { if (args.Value is ValueTuple, I> ctrlArgs) { var (controls, baseArgs) = ctrlArgs; var baseMetadata = this.BaseOp.GetRuntimeMetadata(this.BaseOp.__dataIn(baseArgs)); + if (baseMetadata == null) return null; baseMetadata.IsControlled = true; baseMetadata.Controls = controls.Concat(baseMetadata.Controls); return baseMetadata; diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 967e4c06796..1c7da8e4fd0 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -1,6 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -75,7 +77,8 @@ public Operation(IOperationFactory m) : base(m) [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ControlledOperation Controlled => _controlled.Value; - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => new RuntimeMetadata() { Label = ((ICallable)this).Name, diff --git a/src/Simulation/Core/Operations/OperationPartial.cs b/src/Simulation/Core/Operations/OperationPartial.cs index fe77dd67c3a..5a68394d3eb 100644 --- a/src/Simulation/Core/Operations/OperationPartial.cs +++ b/src/Simulation/Core/Operations/OperationPartial.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -141,7 +143,8 @@ ICallable ICallable.Partial(Func mapper) IUnitary IUnitary

.Partial(Func mapper) => new OperationPartial(this, mapper); - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => this.BaseOp.GetRuntimeMetadata(args); public override string ToString() => $"{this.BaseOp}{{_}}"; diff --git a/src/Simulation/Core/Udts/UDTPartial.cs b/src/Simulation/Core/Udts/UDTPartial.cs index 3b4fccd1b07..96b4925c9d6 100644 --- a/src/Simulation/Core/Udts/UDTPartial.cs +++ b/src/Simulation/Core/Udts/UDTPartial.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -62,7 +64,8 @@ public ICallable Partial(object partialTuple) return (ICallable)Activator.CreateInstance(partialType, new object[] { this, partialTuple }); } - public RuntimeMetadata GetRuntimeMetadata(IApplyData args) => throw new NotImplementedException(); + /// + public RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => throw new NotImplementedException(); internal class DebuggerProxy { diff --git a/src/Simulation/QsharpCore/Intrinsic.cs b/src/Simulation/QsharpCore/Intrinsic.cs index 17813be78e8..8f091203a9f 100644 --- a/src/Simulation/QsharpCore/Intrinsic.cs +++ b/src/Simulation/QsharpCore/Intrinsic.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using Microsoft.Quantum.Simulation.Core; @@ -9,7 +11,8 @@ namespace Microsoft.Quantum.Intrinsic { public partial class CNOT { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { if (args.Value is ValueTuple cnotArgs) { @@ -32,7 +35,8 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) public partial class CCNOT { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { if (args.Value is ValueTuple ccnotArgs) { @@ -55,7 +59,8 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) public partial class M { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { if (args.Value is Qubit target) { @@ -76,11 +81,13 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) public partial class Reset { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; } public partial class ResetAll { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) => null; + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; } } diff --git a/src/Simulation/QsharpCore/Measurement.cs b/src/Simulation/QsharpCore/Measurement.cs index 7061ba0041c..62cf6775fe1 100644 --- a/src/Simulation/QsharpCore/Measurement.cs +++ b/src/Simulation/QsharpCore/Measurement.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System.Collections.Generic; using Microsoft.Quantum.Simulation.Core; @@ -8,7 +10,8 @@ namespace Microsoft.Quantum.Measurement { public partial class MResetX { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { var targets = new List(); var target = args.Value as Qubit; @@ -25,7 +28,8 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) public partial class MResetY { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { var targets = new List(); var target = args.Value as Qubit; @@ -42,7 +46,8 @@ public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) public partial class MResetZ { - public override RuntimeMetadata GetRuntimeMetadata(IApplyData args) + /// + public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { var targets = new List(); var target = args.Value as Qubit; From 045eab225e8420e8d3b545fe3ef42afa5f33ae07 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Tue, 14 Jul 2020 10:05:06 -0400 Subject: [PATCH 04/11] Respond to feedback, add more tests, and modify logic of ArgsToString->GetNonQubitArguments --- src/Simulation/Core/AbstractCallable.cs | 2 +- src/Simulation/Core/Operations/Adjoint.cs | 2 +- src/Simulation/Core/Operations/Controlled.cs | 11 +- src/Simulation/Core/Operations/Operation.cs | 2 +- src/Simulation/Core/RuntimeMetadata.cs | 7 +- src/Simulation/Core/TypeExtensions.cs | 72 ++-- src/Simulation/QsharpCore/Intrinsic.cs | 28 +- .../Simulators.Tests/RuntimeMetadataTests.cs | 320 +++++++++++++++++- .../Simulators.Tests/TypeExtensionsTest.cs | 89 +++++ 9 files changed, 479 insertions(+), 54 deletions(-) create mode 100644 src/Simulation/Simulators.Tests/TypeExtensionsTest.cs diff --git a/src/Simulation/Core/AbstractCallable.cs b/src/Simulation/Core/AbstractCallable.cs index 0da7ceb8d1f..8fc7c712603 100644 --- a/src/Simulation/Core/AbstractCallable.cs +++ b/src/Simulation/Core/AbstractCallable.cs @@ -33,7 +33,7 @@ public AbstractCallable(IOperationFactory m) ///

/// Retrieves the runtime metadata of the Operation. If the Operation has no associated - /// runtime metadata, return null. + /// runtime metadata, returns null. /// public virtual RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; diff --git a/src/Simulation/Core/Operations/Adjoint.cs b/src/Simulation/Core/Operations/Adjoint.cs index d64e8cf4ef7..8e0efe35ad2 100644 --- a/src/Simulation/Core/Operations/Adjoint.cs +++ b/src/Simulation/Core/Operations/Adjoint.cs @@ -79,7 +79,7 @@ public override void Init() { } { var baseMetadata = this.BaseOp.GetRuntimeMetadata(args); if (baseMetadata == null) return null; - baseMetadata.IsAdjoint = true; + baseMetadata.IsAdjoint = !baseMetadata.IsAdjoint; return baseMetadata; } diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index 89fc39184a1..770a9081f6f 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -77,7 +77,7 @@ public override void Init() { } string ICallable.FullName => ((ICallable)this.BaseOp).FullName; OperationFunctor ICallable.Variant => ((ICallable)this.BaseOp).ControlledVariant(); - public override Func<(IQArray, I), QVoid> Body => this.BaseOp.ControlledBody; + public override Func<(IQArray, I), QVoid> Body => this.BaseOp.ControlledBody; public override Func<(IQArray, I), QVoid> AdjointBody => this.BaseOp.ControlledAdjointBody; @@ -116,6 +116,8 @@ public override void Init() { } /// public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { + Debug.Assert(args.Value is ValueTuple, I>, $"Failed to retrieve runtime metadata for {this.ToString()}."); + if (args.Value is ValueTuple, I> ctrlArgs) { var (controls, baseArgs) = ctrlArgs; @@ -125,11 +127,8 @@ public override void Init() { } baseMetadata.Controls = controls.Concat(baseMetadata.Controls); return baseMetadata; } - else - { - Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); - return null; - } + + return null; } diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 1c7da8e4fd0..0c9b0c7bd65 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -82,7 +82,7 @@ public Operation(IOperationFactory m) : base(m) new RuntimeMetadata() { Label = ((ICallable)this).Name, - Args = args.Value.GetType().ArgsToString(args.Value), + Args = args.GetNonQubitArguments(), Targets = args.GetQubits(), }; diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index 655cbe99281..a6fc5ef7514 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -37,6 +37,11 @@ public class RuntimeMetadata /// /// True if operation is composed of multiple operations. /// + ///
+ /// + /// Currently not used as this is intended for compositeoperations, + /// such as ApplyToEach. + /// public bool IsComposite { get; set; } /// @@ -57,4 +62,4 @@ public class RuntimeMetadata /// public IEnumerable Targets { get; set; } = new List(); } -} \ No newline at end of file +} diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index ea887e59c32..1bbba914023 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Collections; using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; @@ -147,35 +148,52 @@ public static Type[] GetTupleFieldTypes(this Type arg) } /// - /// Given a and its arguments, format its non-qubit arguments into a string. - /// Returns null if no arguments found. + /// Given an , retrieve its non-qubit fields as a string. + /// Returns null if no non-qubit fields found. /// - public static string? ArgsToString(this Type t, object args) + public static string? GetNonQubitArguments(this object o) { - var argsStrings = t.GetFields() - .Select(f => - { - var argString = null as string; - - // If field is a tuple, recursively extract its inner arguments and format as a tuple string. - if (f.FieldType.IsTuple()) - { - var nestedArgs = f.GetValue(args); - if (nestedArgs != null) argString = f.FieldType.ArgsToString(nestedArgs); - } - // Add field as an argument if it is not a Qubit type - else if (!f.FieldType.IsQubitsContainer()) - { - argString = f.GetValue(args)?.ToString(); - } - - return argString; - }) - .WhereNotNull(); - - return argsStrings.Any() - ? $"({string.Join(",", argsStrings)})" - : null; + var t = o.GetType(); + + // If object is a Qubit, ignore it (i.e. return null) + if (o is Qubit) return null; + + // If object is an IApplyData, recursively extract nested fields + // and stringify them + if (o is IApplyData data) + { + var argsString = data.Value.GetNonQubitArguments(); + return argsString.Any() ? argsString : null; + } + + // If object is a string, enclose it in quotations + if (o is string s) + { + return (s != null) ? $"\"{s}\"" : null; + } + + // If object is a list, recursively extract its inner arguments and + // concatenate them into a list string + if (typeof(IEnumerable).IsAssignableFrom(t)) + { + var elements = ((IEnumerable)o).Cast() + .Select(x => x.GetNonQubitArguments()) + .WhereNotNull(); + return (elements.Any()) ? $"[{string.Join(", ", elements)}]" : null; + } + + // If object is a tuple, recursively extract its inner arguments and + // concatenate them into a tuple string + if (t.IsTuple()) + { + var items = t.GetFields() + .Select(f => f.GetValue(o).GetNonQubitArguments()) + .WhereNotNull(); + return (items.Any()) ? $"({string.Join(", ", items)})" : null; + } + + // Otherwise, return argument as a string + return (o != null) ? o.ToString() : null; } private static ConcurrentDictionary _normalTypesCache = new ConcurrentDictionary(); diff --git a/src/Simulation/QsharpCore/Intrinsic.cs b/src/Simulation/QsharpCore/Intrinsic.cs index 8f091203a9f..8b53c88abb9 100644 --- a/src/Simulation/QsharpCore/Intrinsic.cs +++ b/src/Simulation/QsharpCore/Intrinsic.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Intrinsic @@ -14,6 +15,8 @@ public partial class CNOT /// public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { + Debug.Assert(args.Value is ValueTuple, $"Failed to retrieve runtime metadata for {this.ToString()}."); + if (args.Value is ValueTuple cnotArgs) { var (ctrl, target) = cnotArgs; @@ -25,11 +28,8 @@ public partial class CNOT Targets = new List() { target }, }; } - else - { - Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); - return null; - } + + return null; } } @@ -38,6 +38,8 @@ public partial class CCNOT /// public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { + Debug.Assert(args.Value is ValueTuple, $"Failed to retrieve runtime metadata for {this.ToString()}."); + if (args.Value is ValueTuple ccnotArgs) { var (ctrl1, ctrl2, target) = ccnotArgs; @@ -49,11 +51,8 @@ public partial class CCNOT Targets = new List() { target }, }; } - else - { - Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); - return null; - } + + return null; } } @@ -62,6 +61,8 @@ public partial class M /// public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) { + Debug.Assert(args.Value is Qubit, $"Failed to retrieve runtime metadata for {this.ToString()}."); + if (args.Value is Qubit target) { return new RuntimeMetadata() @@ -71,11 +72,8 @@ public partial class M Targets = new List() { target }, }; } - else - { - Console.WriteLine($"Failed to retrieve runtime metadata for {this.ToString()}."); - return null; - } + + return null; } } diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 7267d1e8904..24ee934e0bd 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Microsoft.Quantum.Simulation.Core; using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Quantum.Simulation.Core; using Xunit; namespace Microsoft.Quantum.Simulation.Simulators.Tests @@ -15,10 +15,27 @@ public static class IntrinsicTestsExtensions public static bool IsEqual(this RuntimeMetadata self, RuntimeMetadata to) => self.Label == to.Label && self.Args == to.Args && self.IsAdjoint == to.IsAdjoint && self.IsControlled == to.IsControlled && self.IsMeasurement == to.IsMeasurement && - self.IsComposite == to.IsComposite && + self.IsComposite == to.IsComposite && self.Controls.SequenceEqual(to.Controls) && self.Targets.SequenceEqual(to.Targets); } + public class FooOp : Operation>, QVoid>, ICallable + { + public FooOp(IOperationFactory m) : base(m) { } + + public override void Init() { } + + public override Func>, QVoid> Body => + (ValueTuple> data) => null; + + public override IApplyData __dataIn(ValueTuple> data) => + new QTuple>>(data); + + string ICallable.Name => "Foo"; + string ICallable.FullName => "Microsoft.Quantum.Simulation.Simulators.Tests.Foo"; + } + + public class IntrinsicTests { [Fact] @@ -68,6 +85,28 @@ public void CCNOT() Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); } + [Fact] + public void Ry() + { + var target = new FreeQubit(0); + var op = new Microsoft.Quantum.Intrinsic.Ry(new TrivialSimulator()); + var args = op.__dataIn((2.1, target)); + var expected = new RuntimeMetadata() + { + Label = "Ry", + Args = "(2.1)", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + [Fact] public void M() { @@ -177,4 +216,281 @@ public void MResetZ() Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); } } + + public class CustomOpTests + { + [Fact] + public void Foo() + { + Qubit target = new FreeQubit(0); + var op = new FooOp(new TrivialSimulator()); + var args = op.__dataIn(("bar", (target, 2.1))); + var expected = new RuntimeMetadata() + { + Label = "Foo", + Args = "(\"bar\", (2.1))", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + } + + public class ControlledOpTests + { + [Fact] + public void ControlledH() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit target = new FreeQubit(1); + Operation baseOp = new QuantumSimulator().Get(); + var op = new ControlledOperation(baseOp); + var args = op.__dataIn((controls, target)); + var expected = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void ControlledX() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit target = new FreeQubit(1); + Operation baseOp = new QuantumSimulator().Get(); + var op = new ControlledOperation(baseOp); + var args = op.__dataIn((controls, target)); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void ControlledCNOT() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit control = new FreeQubit(1); + Qubit target = new FreeQubit(2); + Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.CNOT(new TrivialSimulator()); + var op = new ControlledOperation, QVoid>(baseOp); + var args = op.__dataIn((controls, (control, target))); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls.Append(control), + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void ControlledCCNOT() + { + Qubit control1 = new FreeQubit(0); + Qubit control2 = new FreeQubit(1); + Qubit control3 = new FreeQubit(2); + Qubit target = new FreeQubit(3); + IQArray controls = new QArray(new[] { control1 }); + Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.CCNOT(new TrivialSimulator()); + var op = new ControlledOperation, QVoid>(baseOp); + var args = op.__dataIn((controls, (control2, control3, target))); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { control1, control2, control3 }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void ControlledFoo() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit target = new FreeQubit(1); + var baseOp = new FooOp(new TrivialSimulator()); + var op = new ControlledOperation>, QVoid>(baseOp); + var args = op.__dataIn((controls, ("bar", (target, 2.1)))); + var expected = new RuntimeMetadata() + { + Label = "Foo", + Args = "(\"bar\", (2.1))", + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + } + + public class AdjointTests + { + [Fact] + public void AdjointH() + { + Qubit target = new FreeQubit(0); + Operation baseOp = new QuantumSimulator().Get(); + var op = new AdjointedOperation(baseOp); + var args = op.__dataIn(target); + var expected = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = true, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void AdjointX() + { + Qubit target = new FreeQubit(0); + Operation baseOp = new QuantumSimulator().Get(); + var op = new AdjointedOperation(baseOp); + var args = op.__dataIn(target); + var expected = new RuntimeMetadata() + { + Label = "X", + Args = null, + IsAdjoint = true, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void AdjointFoo() + { + Qubit target = new FreeQubit(0); + var baseOp = new FooOp(new TrivialSimulator()); + var op = new AdjointedOperation>, QVoid>(baseOp); + var args = op.__dataIn(("bar", (target, 2.1))); + var expected = new RuntimeMetadata() + { + Label = "Foo", + Args = "(\"bar\", (2.1))", + IsAdjoint = true, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + } + + public class PartialOpTests + { + + [Fact] + public void PartialRy() + { + var target = new FreeQubit(0); + Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.Ry(new TrivialSimulator()); + Func, ValueTuple> mapper = (ValueTuple d) => new ValueTuple(d.Item1, target); + var op = new OperationPartial, ValueTuple, QVoid>(baseOp, mapper); + var args = op.__dataIn(new ValueTuple(2.1)); + var expected = new RuntimeMetadata() + { + Label = "Ry", + Args = "(2.1)", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + + [Fact] + public void PartialFoo() + { + var target = new FreeQubit(0); + Operation>, QVoid> baseOp = new FooOp(new TrivialSimulator()); + Func, ValueTuple>> mapper = (ValueTuple d) => new ValueTuple>("bar", (target, d.Item1)); + var op = new OperationPartial, ValueTuple>, QVoid>(baseOp, mapper); + var args = op.__dataIn(new ValueTuple(2.1)); + + var expected = new RuntimeMetadata() + { + Label = "Foo", + Args = "(\"bar\", (2.1))", + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + } + } } diff --git a/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs new file mode 100644 index 00000000000..8e70b4129e7 --- /dev/null +++ b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Core; +using Xunit; + +namespace Microsoft.Quantum.Simulation.Simulators.Tests +{ + public class ApplyData : IApplyData + { + public T Data; + + public ApplyData(T data) + { + this.Data = data; + } + + object IApplyData.Value => this.Data; + + IEnumerable IApplyData.Qubits => QubitsExtractor.Get(typeof(T))?.Extract(Data); + } + + public class GetNonQubitArgumentsTests + { + [Fact] + public void BasicTypes() + { + Assert.Equal("3", 3.GetNonQubitArguments()); + Assert.Equal("False", false.GetNonQubitArguments()); + Assert.Equal("\"Foo\"", "Foo".GetNonQubitArguments()); + Assert.Equal("\"\"", "".GetNonQubitArguments()); + } + + [Fact] + public void TupleTypes() + { + Assert.Equal("(1, 2)", (1, 2).GetNonQubitArguments()); + Assert.Equal("(\"foo\", \"bar\")", ("foo", "bar").GetNonQubitArguments()); + Assert.Equal("(\"foo\", \"bar\", \"\")", ("foo", "bar", "").GetNonQubitArguments()); + Assert.Equal("(\"foo\", (\"bar\", \"car\"))", ("foo", ("bar", "car")).GetNonQubitArguments()); + Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", (("foo", new FreeQubit(0)), ("bar", "car")).GetNonQubitArguments()); + } + + [Fact] + public void ArrayTypes() + { + Assert.Equal("[1, 2, 3]", new[] { 1, 2, 3 }.GetNonQubitArguments()); + Assert.Equal("[\"foo\", \"bar\"]", new[] { "foo", "bar" }.GetNonQubitArguments()); + + var arr = new[] { + (new FreeQubit(0), "foo"), + (new FreeQubit(1), "bar"), + }; + Assert.Equal("[(\"foo\"), (\"bar\")]", arr.GetNonQubitArguments()); + } + + [Fact] + public void IApplyDataTypes() + { + IApplyData data; + data = new ApplyData(3); + Assert.Equal("3", data.GetNonQubitArguments()); + + data = new ApplyData(false); + Assert.Equal("False", data.GetNonQubitArguments()); + + data = new ApplyData("Foo"); + Assert.Equal("\"Foo\"", data.GetNonQubitArguments()); + + data = new ApplyData>((1, "foo")); + Assert.Equal("(1, \"foo\")", data.GetNonQubitArguments()); + + data = new ApplyData, ValueTuple>>((("foo", new FreeQubit(0)), ("bar", "car"))); + Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", data.GetNonQubitArguments()); + + data = new ApplyData(new[] { 1, 2, 3 }); + Assert.Equal("[1, 2, 3]", data.GetNonQubitArguments()); + + var arr = new[] { + (new FreeQubit(0), "foo"), + (new FreeQubit(1), "bar"), + }; + data = new ApplyData<(FreeQubit, string)[]>(arr); + Assert.Equal("[(\"foo\"), (\"bar\")]", data.GetNonQubitArguments()); + } + } +} From 61127d47e3e9407a385ed85ce19ff44361dcd880 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Tue, 14 Jul 2020 17:37:28 -0400 Subject: [PATCH 05/11] Remove override for Reset*'s GetRuntimeMetadata and add more tests --- src/Simulation/Core/RuntimeMetadata.cs | 68 +++- src/Simulation/QsharpCore/Intrinsic.cs | 12 - .../Circuits/RuntimeMetadataTest.qs | 8 + .../Simulators.Tests/RuntimeMetadataTests.cs | 369 +++++++++++++----- 4 files changed, 347 insertions(+), 110 deletions(-) create mode 100644 src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index a6fc5ef7514..37e9709bc42 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -3,7 +3,9 @@ #nullable enable +using System; using System.Collections.Generic; +using System.Linq; namespace Microsoft.Quantum.Simulation.Core { @@ -45,7 +47,7 @@ public class RuntimeMetadata public bool IsComposite { get; set; } /// - /// Group of operations for each classical branch. + /// Group of operations for each classical branch (true and false). /// /// /// Currently not used as this is intended for classically-controlled operations. @@ -61,5 +63,69 @@ public class RuntimeMetadata /// List of target registers. /// public IEnumerable Targets { get; set; } = new List(); + + private static bool OnlyOneNull(object? a, object? b) => + (a == null && b != null) || (b == null && a != null); + + private static bool IsBothNull(object? a, object? b) => + a == null && b == null; + + private static bool ListEquals(IEnumerable a, IEnumerable b) => + IsBothNull(a, b) || (!OnlyOneNull(a, b) && a.SequenceEqual(b)); + + public override bool Equals(object? obj) + { + var other = obj as RuntimeMetadata; + + if (other is null) return false; + + if (!ListEquals(this.Controls, other.Controls)) return false; + + if (!ListEquals(this.Targets, other.Targets)) return false; + + // If only one children is null, return false + if (OnlyOneNull(this.Children, other.Children)) return false; + + // If both children are not null, compare each child element-wise and return + // false if any of them are not equal + if (!IsBothNull(this.Children, other.Children)) + { + if (this.Children.Count() != other.Children.Count() || + this.Children.Zip(other.Children, ListEquals).Contains(false)) + return false; + } + + return this.Label == other.Label && this.Args == other.Args && + this.IsAdjoint == other.IsAdjoint && this.IsControlled == other.IsControlled && + this.IsMeasurement == other.IsMeasurement && this.IsComposite == other.IsComposite; + } + + public override int GetHashCode() + { + // Stringify qubits, concatenate as string, and get resulting hashcode + var controlsHash = string.Join(",", this.Controls.Select(q => q.ToString())).GetHashCode(); + var targetsHash = string.Join(",", this.Targets.Select(q => q.ToString())).GetHashCode(); + + // Recursively get hashcode of inner `RuntimeMetadata` objects, concatenate into a string, + // and get resulting hashcode + var childrenHash = (this.Children != null) + ? string.Join(", ", this.Children.Select(child => (child != null) + ? string.Join(",", child.Select(m => m?.GetHashCode().ToString() ?? "0")) + : "0" + )).GetHashCode() + : 0; + + // Combine all other properties and get the resulting hashcode + var otherHash = HashCode.Combine(this.Label, this.Args, this.IsAdjoint, this.IsControlled, + this.IsMeasurement, this.IsComposite); + + // Combine them all together to get the final hashcode + return HashCode.Combine(controlsHash, targetsHash, childrenHash, otherHash); + } + + public static bool operator ==(RuntimeMetadata? x, RuntimeMetadata? y) => + IsBothNull(x, y) || (x?.Equals(y) ?? false); + + public static bool operator !=(RuntimeMetadata? x, RuntimeMetadata? y) => !(x == y); } } diff --git a/src/Simulation/QsharpCore/Intrinsic.cs b/src/Simulation/QsharpCore/Intrinsic.cs index 8b53c88abb9..76976a0f217 100644 --- a/src/Simulation/QsharpCore/Intrinsic.cs +++ b/src/Simulation/QsharpCore/Intrinsic.cs @@ -76,16 +76,4 @@ public partial class M return null; } } - - public partial class Reset - { - /// - public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; - } - - public partial class ResetAll - { - /// - public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => null; - } } diff --git a/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs new file mode 100644 index 00000000000..e74058917e4 --- /dev/null +++ b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { + + operation FooUDT (foo : String, (q : Qubit, d : Double)) : Unit is Ctl + Adj { } + +} diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 24ee934e0bd..31902622f77 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.Linq; @@ -9,32 +11,157 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests { - public static class IntrinsicTestsExtensions + public class RuntimeMetadataEqualityTests { - // Look into better ways of checking equality (i.e. GetType().GetProperties()) - public static bool IsEqual(this RuntimeMetadata self, RuntimeMetadata to) => - self.Label == to.Label && self.Args == to.Args && self.IsAdjoint == to.IsAdjoint && - self.IsControlled == to.IsControlled && self.IsMeasurement == to.IsMeasurement && - self.IsComposite == to.IsComposite && - self.Controls.SequenceEqual(to.Controls) && self.Targets.SequenceEqual(to.Targets); - } + [Fact] + public void WrongType() + { + RuntimeMetadata a = new RuntimeMetadata { }; + var i = 5; + Assert.False(a.Equals(i)); + } - public class FooOp : Operation>, QVoid>, ICallable - { - public FooOp(IOperationFactory m) : base(m) { } + [Fact] + public void NullEquality() + { + RuntimeMetadata a = new RuntimeMetadata { }; + Assert.False(a == null); + Assert.False(null == a); + Assert.True(null == null); + } - public override void Init() { } + [Fact] + public void CheckEquality() + { + var a = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { }, + }; + var b = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { }, + }; + Assert.True(a == b); - public override Func>, QVoid> Body => - (ValueTuple> data) => null; + b.Label = "X"; + Assert.False(a == b); + b.Label = "H"; - public override IApplyData __dataIn(ValueTuple> data) => - new QTuple>>(data); + b.Args = "(1)"; + Assert.False(a == b); + b.Args = null; - string ICallable.Name => "Foo"; - string ICallable.FullName => "Microsoft.Quantum.Simulation.Simulators.Tests.Foo"; - } + b.IsAdjoint = true; + Assert.False(a == b); + b.IsAdjoint = false; + + b.IsControlled = true; + Assert.False(a == b); + b.IsControlled = false; + + b.IsMeasurement = true; + Assert.False(a == b); + b.IsMeasurement = false; + + b.IsComposite = true; + Assert.False(a == b); + b.IsComposite = false; + } + + [Fact] + public void ControlsEquality() + { + var a = new RuntimeMetadata() + { + Controls = new List() { }, + }; + var b = new RuntimeMetadata() + { + Controls = new List() { }, + }; + Assert.True(a == b); + + b.Controls = new List() { new FreeQubit(1) }; + Assert.False(a == b); + a.Controls = new List() { new FreeQubit(1) }; + Assert.True(a == b); + } + + [Fact] + public void TargetsEquality() + { + var a = new RuntimeMetadata() + { + Targets = new List() { }, + }; + var b = new RuntimeMetadata() + { + Targets = new List() { }, + }; + Assert.True(a == b); + + b.Targets = new List() { new FreeQubit(1) }; + Assert.False(a == b); + + a.Targets = new List() { new FreeQubit(1) }; + Assert.True(a == b); + } + + [Fact] + public void ChildrenEquality() + { + var a = new RuntimeMetadata() + { + Children = new[] + { + new List(), + new List(), + }, + }; + var b = new RuntimeMetadata() + { + Children = new[] + { + new List(), + new List(), + }, + }; + Assert.True(a == b); + + var aChildren = a.Children.ToList(); + aChildren[0] = new List() { new RuntimeMetadata() { Label = "H" } }; + a.Children = aChildren; + Assert.False(a == b); + + var bChildren = b.Children.ToList(); + bChildren[0] = new List() { new RuntimeMetadata() { Label = "X" } }; + b.Children = bChildren; + Assert.False(a == b); + + bChildren[0] = new List() { new RuntimeMetadata() { Label = "H" } }; + Assert.True(a == b); + + b.Children = b.Children.SkipLast(1); + Assert.False(a == b); + } + } public class IntrinsicTests { @@ -43,7 +170,7 @@ public void CNOT() { var control = new FreeQubit(1); var target = new FreeQubit(0); - var op = new Microsoft.Quantum.Intrinsic.CNOT(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn((control, target)); var expected = new RuntimeMetadata() { @@ -58,7 +185,10 @@ public void CNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + var metadata = op.GetRuntimeMetadata(args); + var equals = metadata == expected; + + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] @@ -67,7 +197,7 @@ public void CCNOT() var control1 = new FreeQubit(0); var control2 = new FreeQubit(2); var target = new FreeQubit(1); - var op = new Microsoft.Quantum.Intrinsic.CCNOT(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn((control1, control2, target)); var expected = new RuntimeMetadata() { @@ -82,14 +212,14 @@ public void CCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] public void Ry() { var target = new FreeQubit(0); - var op = new Microsoft.Quantum.Intrinsic.Ry(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn((2.1, target)); var expected = new RuntimeMetadata() { @@ -104,14 +234,14 @@ public void Ry() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] public void M() { var measureQubit = new FreeQubit(0); - var op = new Microsoft.Quantum.Intrinsic.M(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn(measureQubit); var expected = new RuntimeMetadata() { @@ -126,25 +256,7 @@ public void M() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); - } - - [Fact] - public void Reset() - { - var target = new FreeQubit(0); - var op = new Microsoft.Quantum.Intrinsic.Reset(new TrivialSimulator()); - var args = op.__dataIn(target); - Assert.Null(op.GetRuntimeMetadata(args)); - } - - [Fact] - public void ResetAll() - { - var targets = QArray.Create(3); - var op = new Microsoft.Quantum.Intrinsic.ResetAll(new TrivialSimulator()); - var args = op.__dataIn(targets); - Assert.Null(op.GetRuntimeMetadata(args)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } } @@ -154,7 +266,7 @@ public class MeasurementTests public void MResetX() { var measureQubit = new FreeQubit(0); - var op = new Microsoft.Quantum.Measurement.MResetX(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn(measureQubit); var expected = new RuntimeMetadata() { @@ -169,14 +281,14 @@ public void MResetX() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] public void MResetY() { var measureQubit = new FreeQubit(0); - var op = new Microsoft.Quantum.Measurement.MResetY(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn(measureQubit); var expected = new RuntimeMetadata() { @@ -191,14 +303,14 @@ public void MResetY() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] public void MResetZ() { var measureQubit = new FreeQubit(0); - var op = new Microsoft.Quantum.Measurement.MResetZ(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn(measureQubit); var expected = new RuntimeMetadata() { @@ -213,21 +325,21 @@ public void MResetZ() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } } - public class CustomOpTests + public class UDTTests { [Fact] - public void Foo() + public void FooUDT() { Qubit target = new FreeQubit(0); - var op = new FooOp(new TrivialSimulator()); + var op = new QuantumSimulator().Get(); var args = op.__dataIn(("bar", (target, 2.1))); var expected = new RuntimeMetadata() { - Label = "Foo", + Label = "FooUDT", Args = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = false, @@ -238,7 +350,7 @@ public void Foo() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } } @@ -249,8 +361,7 @@ public void ControlledH() { IQArray controls = new QArray(new[] { new FreeQubit(0) }); Qubit target = new FreeQubit(1); - Operation baseOp = new QuantumSimulator().Get(); - var op = new ControlledOperation(baseOp); + var op = new QuantumSimulator().Get().Controlled; var args = op.__dataIn((controls, target)); var expected = new RuntimeMetadata() { @@ -265,7 +376,7 @@ public void ControlledH() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] @@ -273,8 +384,7 @@ public void ControlledX() { IQArray controls = new QArray(new[] { new FreeQubit(0) }); Qubit target = new FreeQubit(1); - Operation baseOp = new QuantumSimulator().Get(); - var op = new ControlledOperation(baseOp); + var op = new QuantumSimulator().Get().Controlled; var args = op.__dataIn((controls, target)); var expected = new RuntimeMetadata() { @@ -289,7 +399,7 @@ public void ControlledX() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] @@ -298,8 +408,7 @@ public void ControlledCNOT() IQArray controls = new QArray(new[] { new FreeQubit(0) }); Qubit control = new FreeQubit(1); Qubit target = new FreeQubit(2); - Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.CNOT(new TrivialSimulator()); - var op = new ControlledOperation, QVoid>(baseOp); + var op = new QuantumSimulator().Get().Controlled; var args = op.__dataIn((controls, (control, target))); var expected = new RuntimeMetadata() { @@ -314,7 +423,7 @@ public void ControlledCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] @@ -325,8 +434,7 @@ public void ControlledCCNOT() Qubit control3 = new FreeQubit(2); Qubit target = new FreeQubit(3); IQArray controls = new QArray(new[] { control1 }); - Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.CCNOT(new TrivialSimulator()); - var op = new ControlledOperation, QVoid>(baseOp); + var op = new QuantumSimulator().Get().Controlled; var args = op.__dataIn((controls, (control2, control3, target))); var expected = new RuntimeMetadata() { @@ -341,20 +449,19 @@ public void ControlledCCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] - public void ControlledFoo() + public void ControlledUDT() { IQArray controls = new QArray(new[] { new FreeQubit(0) }); Qubit target = new FreeQubit(1); - var baseOp = new FooOp(new TrivialSimulator()); - var op = new ControlledOperation>, QVoid>(baseOp); + var op = new QuantumSimulator().Get().Controlled; var args = op.__dataIn((controls, ("bar", (target, 2.1)))); var expected = new RuntimeMetadata() { - Label = "Foo", + Label = "FooUDT", Args = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = true, @@ -365,7 +472,7 @@ public void ControlledFoo() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } } @@ -375,8 +482,7 @@ public class AdjointTests public void AdjointH() { Qubit target = new FreeQubit(0); - Operation baseOp = new QuantumSimulator().Get(); - var op = new AdjointedOperation(baseOp); + var op = new QuantumSimulator().Get().Adjoint; var args = op.__dataIn(target); var expected = new RuntimeMetadata() { @@ -391,15 +497,14 @@ public void AdjointH() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] public void AdjointX() { Qubit target = new FreeQubit(0); - Operation baseOp = new QuantumSimulator().Get(); - var op = new AdjointedOperation(baseOp); + var op = new QuantumSimulator().Get().Adjoint; var args = op.__dataIn(target); var expected = new RuntimeMetadata() { @@ -414,19 +519,18 @@ public void AdjointX() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] - public void AdjointFoo() + public void AdjointUDT() { Qubit target = new FreeQubit(0); - var baseOp = new FooOp(new TrivialSimulator()); - var op = new AdjointedOperation>, QVoid>(baseOp); + var op = new QuantumSimulator().Get().Adjoint; var args = op.__dataIn(("bar", (target, 2.1))); var expected = new RuntimeMetadata() { - Label = "Foo", + Label = "FooUDT", Args = "(\"bar\", (2.1))", IsAdjoint = true, IsControlled = false, @@ -437,7 +541,81 @@ public void AdjointFoo() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); + } + + [Fact] + public void AdjointAdjointH() + { + Qubit target = new FreeQubit(0); + var op = new QuantumSimulator().Get().Adjoint.Adjoint; + var args = op.__dataIn(target); + var expected = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = false, + IsControlled = false, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = new List() { }, + Targets = new List() { target }, + }; + + Assert.True(op.GetRuntimeMetadata(args) == expected); + } + + [Fact] + public void ControlledAdjointH() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit target = new FreeQubit(1); + var op1 = new QuantumSimulator().Get().Controlled.Adjoint; + var op2 = new QuantumSimulator().Get().Adjoint.Controlled; + var args = op1.__dataIn((controls, target)); + var expected = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = true, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls, + Targets = new List() { target }, + }; + + Assert.True(op1.GetRuntimeMetadata(args) == expected); + Assert.True(op2.GetRuntimeMetadata(args) == expected); + } + + [Fact] + public void ControlledAdjointAdjointH() + { + IQArray controls = new QArray(new[] { new FreeQubit(0) }); + Qubit target = new FreeQubit(1); + var op1 = new QuantumSimulator().Get().Controlled.Adjoint.Adjoint; + var op2 = new QuantumSimulator().Get().Adjoint.Controlled.Adjoint; + var op3 = new QuantumSimulator().Get().Adjoint.Adjoint.Controlled; + var args = op1.__dataIn((controls, target)); + var expected = new RuntimeMetadata() + { + Label = "H", + Args = null, + IsAdjoint = false, + IsControlled = true, + IsMeasurement = false, + IsComposite = false, + Children = null, + Controls = controls, + Targets = new List() { target }, + }; + + Assert.True(op1.GetRuntimeMetadata(args) == expected); + Assert.True(op2.GetRuntimeMetadata(args) == expected); + Assert.True(op3.GetRuntimeMetadata(args) == expected); } } @@ -448,10 +626,9 @@ public class PartialOpTests public void PartialRy() { var target = new FreeQubit(0); - Operation, QVoid> baseOp = new Microsoft.Quantum.Intrinsic.Ry(new TrivialSimulator()); - Func, ValueTuple> mapper = (ValueTuple d) => new ValueTuple(d.Item1, target); - var op = new OperationPartial, ValueTuple, QVoid>(baseOp, mapper); - var args = op.__dataIn(new ValueTuple(2.1)); + var op = new QuantumSimulator().Get().Partial((double d) => + new ValueTuple(d, target)); + var args = op.__dataIn(2.1); var expected = new RuntimeMetadata() { Label = "Ry", @@ -465,21 +642,19 @@ public void PartialRy() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } [Fact] - public void PartialFoo() + public void PartialUDT() { var target = new FreeQubit(0); - Operation>, QVoid> baseOp = new FooOp(new TrivialSimulator()); - Func, ValueTuple>> mapper = (ValueTuple d) => new ValueTuple>("bar", (target, d.Item1)); - var op = new OperationPartial, ValueTuple>, QVoid>(baseOp, mapper); - var args = op.__dataIn(new ValueTuple(2.1)); - + var op = new QuantumSimulator().Get().Partial((double d) => + new ValueTuple>("bar", (target, d))); + var args = op.__dataIn(2.1); var expected = new RuntimeMetadata() { - Label = "Foo", + Label = "FooUDT", Args = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = false, @@ -490,7 +665,7 @@ public void PartialFoo() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args).IsEqual(expected)); + Assert.True(op.GetRuntimeMetadata(args) == expected); } } } From a50ad48a5efaddd0c7e184c666006fc684703db3 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Tue, 14 Jul 2020 20:36:16 -0400 Subject: [PATCH 06/11] Implement GetRuntimeMetadata for UDTPartial --- src/Simulation/Core/Operations/Operation.cs | 2 +- src/Simulation/Core/TypeExtensions.cs | 8 ++-- src/Simulation/Core/Udts/UDTPartial.cs | 11 ++++- .../Circuits/RuntimeMetadataTest.qs | 4 +- .../Simulators.Tests/RuntimeMetadataTests.cs | 28 ++++++------- .../Simulators.Tests/TypeExtensionsTest.cs | 40 +++++++++---------- 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 0c9b0c7bd65..48a2b13b9da 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -82,7 +82,7 @@ public Operation(IOperationFactory m) : base(m) new RuntimeMetadata() { Label = ((ICallable)this).Name, - Args = args.GetNonQubitArguments(), + Args = args.GetNonQubitArgumentsAsString(), Targets = args.GetQubits(), }; diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index 1bbba914023..d710f1c8617 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -151,7 +151,7 @@ public static Type[] GetTupleFieldTypes(this Type arg) /// Given an , retrieve its non-qubit fields as a string. /// Returns null if no non-qubit fields found. /// - public static string? GetNonQubitArguments(this object o) + public static string? GetNonQubitArgumentsAsString(this object o) { var t = o.GetType(); @@ -162,7 +162,7 @@ public static Type[] GetTupleFieldTypes(this Type arg) // and stringify them if (o is IApplyData data) { - var argsString = data.Value.GetNonQubitArguments(); + var argsString = data.Value.GetNonQubitArgumentsAsString(); return argsString.Any() ? argsString : null; } @@ -177,7 +177,7 @@ public static Type[] GetTupleFieldTypes(this Type arg) if (typeof(IEnumerable).IsAssignableFrom(t)) { var elements = ((IEnumerable)o).Cast() - .Select(x => x.GetNonQubitArguments()) + .Select(x => x.GetNonQubitArgumentsAsString()) .WhereNotNull(); return (elements.Any()) ? $"[{string.Join(", ", elements)}]" : null; } @@ -187,7 +187,7 @@ public static Type[] GetTupleFieldTypes(this Type arg) if (t.IsTuple()) { var items = t.GetFields() - .Select(f => f.GetValue(o).GetNonQubitArguments()) + .Select(f => f.GetValue(o).GetNonQubitArgumentsAsString()) .WhereNotNull(); return (items.Any()) ? $"({string.Join(", ", items)})" : null; } diff --git a/src/Simulation/Core/Udts/UDTPartial.cs b/src/Simulation/Core/Udts/UDTPartial.cs index 96b4925c9d6..da2554af5b9 100644 --- a/src/Simulation/Core/Udts/UDTPartial.cs +++ b/src/Simulation/Core/Udts/UDTPartial.cs @@ -65,7 +65,16 @@ public ICallable Partial(object partialTuple) } /// - public RuntimeMetadata? GetRuntimeMetadata(IApplyData args) => throw new NotImplementedException(); + public RuntimeMetadata? GetRuntimeMetadata(IApplyData args) + { + Debug.Assert(args.Value is P, $"Failed to retrieve runtime metadata for {typeof(U).Name}."); + var baseArgs = this.Apply((P) args.Value); + return new RuntimeMetadata() + { + Label = typeof(U).Name, + Args = baseArgs?.GetNonQubitArgumentsAsString(), + }; + } internal class DebuggerProxy { diff --git a/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs index e74058917e4..dcb7df85c86 100644 --- a/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs +++ b/src/Simulation/Simulators.Tests/Circuits/RuntimeMetadataTest.qs @@ -3,6 +3,8 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { - operation FooUDT (foo : String, (q : Qubit, d : Double)) : Unit is Ctl + Adj { } + newtype FooUDT = (String, (Qubit, Double)); + + operation FooUDTOp (foo : FooUDT) : Unit is Ctl + Adj { } } diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 31902622f77..2c765b7ef40 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -332,14 +332,14 @@ public void MResetZ() public class UDTTests { [Fact] - public void FooUDT() + public void FooUDTOp() { Qubit target = new FreeQubit(0); - var op = new QuantumSimulator().Get(); - var args = op.__dataIn(("bar", (target, 2.1))); + var op = new QuantumSimulator().Get(); + var args = op.__dataIn(new Circuits.FooUDT(("bar", (target, 2.1)))); var expected = new RuntimeMetadata() { - Label = "FooUDT", + Label = "FooUDTOp", Args = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = false, @@ -457,11 +457,11 @@ public void ControlledUDT() { IQArray controls = new QArray(new[] { new FreeQubit(0) }); Qubit target = new FreeQubit(1); - var op = new QuantumSimulator().Get().Controlled; - var args = op.__dataIn((controls, ("bar", (target, 2.1)))); + var op = new QuantumSimulator().Get().Controlled; + var args = new QTuple, Circuits.FooUDT>>((controls, new Circuits.FooUDT(("bar", (target, 2.1))))); var expected = new RuntimeMetadata() { - Label = "FooUDT", + Label = "FooUDTOp", Args = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = true, @@ -526,11 +526,11 @@ public void AdjointX() public void AdjointUDT() { Qubit target = new FreeQubit(0); - var op = new QuantumSimulator().Get().Adjoint; - var args = op.__dataIn(("bar", (target, 2.1))); + var op = new QuantumSimulator().Get().Adjoint; + var args = op.__dataIn(new Circuits.FooUDT(("bar", (target, 2.1)))); var expected = new RuntimeMetadata() { - Label = "FooUDT", + Label = "FooUDTOp", Args = "(\"bar\", (2.1))", IsAdjoint = true, IsControlled = false, @@ -649,9 +649,9 @@ public void PartialRy() public void PartialUDT() { var target = new FreeQubit(0); - var op = new QuantumSimulator().Get().Partial((double d) => - new ValueTuple>("bar", (target, d))); - var args = op.__dataIn(2.1); + var op = new QuantumSimulator().Get>(typeof(Circuits.FooUDT)) + .Partial((double d) => (("bar", (target, d)))); + var args = new QTuple(2.1); var expected = new RuntimeMetadata() { Label = "FooUDT", @@ -662,7 +662,7 @@ public void PartialUDT() IsComposite = false, Children = null, Controls = new List() { }, - Targets = new List() { target }, + Targets = new List() { }, }; Assert.True(op.GetRuntimeMetadata(args) == expected); diff --git a/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs index 8e70b4129e7..8e025482316 100644 --- a/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs +++ b/src/Simulation/Simulators.Tests/TypeExtensionsTest.cs @@ -22,38 +22,38 @@ public ApplyData(T data) IEnumerable IApplyData.Qubits => QubitsExtractor.Get(typeof(T))?.Extract(Data); } - public class GetNonQubitArgumentsTests + public class GetNonQubitArgumentsAsStringTests { [Fact] public void BasicTypes() { - Assert.Equal("3", 3.GetNonQubitArguments()); - Assert.Equal("False", false.GetNonQubitArguments()); - Assert.Equal("\"Foo\"", "Foo".GetNonQubitArguments()); - Assert.Equal("\"\"", "".GetNonQubitArguments()); + Assert.Equal("3", 3.GetNonQubitArgumentsAsString()); + Assert.Equal("False", false.GetNonQubitArgumentsAsString()); + Assert.Equal("\"Foo\"", "Foo".GetNonQubitArgumentsAsString()); + Assert.Equal("\"\"", "".GetNonQubitArgumentsAsString()); } [Fact] public void TupleTypes() { - Assert.Equal("(1, 2)", (1, 2).GetNonQubitArguments()); - Assert.Equal("(\"foo\", \"bar\")", ("foo", "bar").GetNonQubitArguments()); - Assert.Equal("(\"foo\", \"bar\", \"\")", ("foo", "bar", "").GetNonQubitArguments()); - Assert.Equal("(\"foo\", (\"bar\", \"car\"))", ("foo", ("bar", "car")).GetNonQubitArguments()); - Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", (("foo", new FreeQubit(0)), ("bar", "car")).GetNonQubitArguments()); + Assert.Equal("(1, 2)", (1, 2).GetNonQubitArgumentsAsString()); + Assert.Equal("(\"foo\", \"bar\")", ("foo", "bar").GetNonQubitArgumentsAsString()); + 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()); } [Fact] public void ArrayTypes() { - Assert.Equal("[1, 2, 3]", new[] { 1, 2, 3 }.GetNonQubitArguments()); - Assert.Equal("[\"foo\", \"bar\"]", new[] { "foo", "bar" }.GetNonQubitArguments()); + Assert.Equal("[1, 2, 3]", new[] { 1, 2, 3 }.GetNonQubitArgumentsAsString()); + Assert.Equal("[\"foo\", \"bar\"]", new[] { "foo", "bar" }.GetNonQubitArgumentsAsString()); var arr = new[] { (new FreeQubit(0), "foo"), (new FreeQubit(1), "bar"), }; - Assert.Equal("[(\"foo\"), (\"bar\")]", arr.GetNonQubitArguments()); + Assert.Equal("[(\"foo\"), (\"bar\")]", arr.GetNonQubitArgumentsAsString()); } [Fact] @@ -61,29 +61,29 @@ public void IApplyDataTypes() { IApplyData data; data = new ApplyData(3); - Assert.Equal("3", data.GetNonQubitArguments()); + Assert.Equal("3", data.GetNonQubitArgumentsAsString()); data = new ApplyData(false); - Assert.Equal("False", data.GetNonQubitArguments()); + Assert.Equal("False", data.GetNonQubitArgumentsAsString()); data = new ApplyData("Foo"); - Assert.Equal("\"Foo\"", data.GetNonQubitArguments()); + Assert.Equal("\"Foo\"", data.GetNonQubitArgumentsAsString()); data = new ApplyData>((1, "foo")); - Assert.Equal("(1, \"foo\")", data.GetNonQubitArguments()); + Assert.Equal("(1, \"foo\")", data.GetNonQubitArgumentsAsString()); data = new ApplyData, ValueTuple>>((("foo", new FreeQubit(0)), ("bar", "car"))); - Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", data.GetNonQubitArguments()); + Assert.Equal("((\"foo\"), (\"bar\", \"car\"))", data.GetNonQubitArgumentsAsString()); data = new ApplyData(new[] { 1, 2, 3 }); - Assert.Equal("[1, 2, 3]", data.GetNonQubitArguments()); + Assert.Equal("[1, 2, 3]", data.GetNonQubitArgumentsAsString()); var arr = new[] { (new FreeQubit(0), "foo"), (new FreeQubit(1), "bar"), }; data = new ApplyData<(FreeQubit, string)[]>(arr); - Assert.Equal("[(\"foo\"), (\"bar\")]", data.GetNonQubitArguments()); + Assert.Equal("[(\"foo\"), (\"bar\")]", data.GetNonQubitArgumentsAsString()); } } } From e6e42ac74002793247617ece37a853a9fbd2fd09 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Tue, 14 Jul 2020 20:59:40 -0400 Subject: [PATCH 07/11] Rename Args to FormattedNonQubitArgs --- src/Simulation/Core/Operations/Operation.cs | 2 +- src/Simulation/Core/RuntimeMetadata.cs | 8 +-- src/Simulation/Core/Udts/UDTPartial.cs | 2 +- .../Simulators.Tests/RuntimeMetadataTests.cs | 50 +++++++++---------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 48a2b13b9da..1dd146c4f22 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -82,7 +82,7 @@ public Operation(IOperationFactory m) : base(m) new RuntimeMetadata() { Label = ((ICallable)this).Name, - Args = args.GetNonQubitArgumentsAsString(), + FormattedNonQubitArgs = args.GetNonQubitArgumentsAsString() ?? "", Targets = args.GetQubits(), }; diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index 37e9709bc42..4ff67d64264 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -17,9 +17,9 @@ public class RuntimeMetadata public string Label { get; set; } = ""; /// - /// Non-qubit arguments provided to gate. + /// Non-qubit arguments provided to gate, formatted as string. /// - public string? Args { get; set; } + public string FormattedNonQubitArgs { get; set; } = ""; /// /// True if operation is an adjoint operation. @@ -95,7 +95,7 @@ public override bool Equals(object? obj) return false; } - return this.Label == other.Label && this.Args == other.Args && + return this.Label == other.Label && this.FormattedNonQubitArgs == other.FormattedNonQubitArgs && this.IsAdjoint == other.IsAdjoint && this.IsControlled == other.IsControlled && this.IsMeasurement == other.IsMeasurement && this.IsComposite == other.IsComposite; } @@ -116,7 +116,7 @@ public override int GetHashCode() : 0; // Combine all other properties and get the resulting hashcode - var otherHash = HashCode.Combine(this.Label, this.Args, this.IsAdjoint, this.IsControlled, + var otherHash = HashCode.Combine(this.Label, this.FormattedNonQubitArgs, this.IsAdjoint, this.IsControlled, this.IsMeasurement, this.IsComposite); // Combine them all together to get the final hashcode diff --git a/src/Simulation/Core/Udts/UDTPartial.cs b/src/Simulation/Core/Udts/UDTPartial.cs index da2554af5b9..a97a92f870f 100644 --- a/src/Simulation/Core/Udts/UDTPartial.cs +++ b/src/Simulation/Core/Udts/UDTPartial.cs @@ -72,7 +72,7 @@ public ICallable Partial(object partialTuple) return new RuntimeMetadata() { Label = typeof(U).Name, - Args = baseArgs?.GetNonQubitArgumentsAsString(), + FormattedNonQubitArgs = baseArgs?.GetNonQubitArgumentsAsString() ?? "", }; } diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 2c765b7ef40..0bcc8a42cd0 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -36,7 +36,7 @@ public void CheckEquality() var a = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -48,7 +48,7 @@ public void CheckEquality() var b = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -63,9 +63,9 @@ public void CheckEquality() Assert.False(a == b); b.Label = "H"; - b.Args = "(1)"; + b.FormattedNonQubitArgs = "(1)"; Assert.False(a == b); - b.Args = null; + b.FormattedNonQubitArgs = ""; b.IsAdjoint = true; Assert.False(a == b); @@ -175,7 +175,7 @@ public void CNOT() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -202,7 +202,7 @@ public void CCNOT() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -224,7 +224,7 @@ public void Ry() var expected = new RuntimeMetadata() { Label = "Ry", - Args = "(2.1)", + FormattedNonQubitArgs = "(2.1)", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -246,7 +246,7 @@ public void M() var expected = new RuntimeMetadata() { Label = "M", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = true, @@ -271,7 +271,7 @@ public void MResetX() var expected = new RuntimeMetadata() { Label = "MResetX", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = true, @@ -293,7 +293,7 @@ public void MResetY() var expected = new RuntimeMetadata() { Label = "MResetY", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = true, @@ -315,7 +315,7 @@ public void MResetZ() var expected = new RuntimeMetadata() { Label = "MResetZ", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = true, @@ -340,7 +340,7 @@ public void FooUDTOp() var expected = new RuntimeMetadata() { Label = "FooUDTOp", - Args = "(\"bar\", (2.1))", + FormattedNonQubitArgs = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -366,7 +366,7 @@ public void ControlledH() var expected = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -389,7 +389,7 @@ public void ControlledX() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -413,7 +413,7 @@ public void ControlledCNOT() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -439,7 +439,7 @@ public void ControlledCCNOT() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -462,7 +462,7 @@ public void ControlledUDT() var expected = new RuntimeMetadata() { Label = "FooUDTOp", - Args = "(\"bar\", (2.1))", + FormattedNonQubitArgs = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -487,7 +487,7 @@ public void AdjointH() var expected = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = true, IsControlled = false, IsMeasurement = false, @@ -509,7 +509,7 @@ public void AdjointX() var expected = new RuntimeMetadata() { Label = "X", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = true, IsControlled = false, IsMeasurement = false, @@ -531,7 +531,7 @@ public void AdjointUDT() var expected = new RuntimeMetadata() { Label = "FooUDTOp", - Args = "(\"bar\", (2.1))", + FormattedNonQubitArgs = "(\"bar\", (2.1))", IsAdjoint = true, IsControlled = false, IsMeasurement = false, @@ -553,7 +553,7 @@ public void AdjointAdjointH() var expected = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -577,7 +577,7 @@ public void ControlledAdjointH() var expected = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = true, IsControlled = true, IsMeasurement = false, @@ -603,7 +603,7 @@ public void ControlledAdjointAdjointH() var expected = new RuntimeMetadata() { Label = "H", - Args = null, + FormattedNonQubitArgs = "", IsAdjoint = false, IsControlled = true, IsMeasurement = false, @@ -632,7 +632,7 @@ public void PartialRy() var expected = new RuntimeMetadata() { Label = "Ry", - Args = "(2.1)", + FormattedNonQubitArgs = "(2.1)", IsAdjoint = false, IsControlled = false, IsMeasurement = false, @@ -655,7 +655,7 @@ public void PartialUDT() var expected = new RuntimeMetadata() { Label = "FooUDT", - Args = "(\"bar\", (2.1))", + FormattedNonQubitArgs = "(\"bar\", (2.1))", IsAdjoint = false, IsControlled = false, IsMeasurement = false, From b7375810196e9ee8ecd2bc0ed164d85f4ae6fcb2 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Wed, 15 Jul 2020 11:13:23 -0400 Subject: [PATCH 08/11] Respond to PR feedback --- src/Simulation/Core/RuntimeMetadata.cs | 18 +- .../Simulators.Tests/RuntimeMetadataTests.cs | 157 +++++++----------- 2 files changed, 76 insertions(+), 99 deletions(-) diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index 4ff67d64264..decbe223858 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -9,6 +9,9 @@ namespace Microsoft.Quantum.Simulation.Core { + /// + /// Contains the metadata associated with an operation's runtime execution path. + /// public class RuntimeMetadata { /// @@ -79,6 +82,11 @@ public override bool Equals(object? obj) if (other is null) return false; + if (this.Label != other.Label || this.FormattedNonQubitArgs != other.FormattedNonQubitArgs || + this.IsAdjoint != other.IsAdjoint || this.IsControlled != other.IsControlled || + this.IsMeasurement != other.IsMeasurement || this.IsComposite != other.IsComposite) + return false; + if (!ListEquals(this.Controls, other.Controls)) return false; if (!ListEquals(this.Targets, other.Targets)) return false; @@ -94,17 +102,15 @@ public override bool Equals(object? obj) this.Children.Zip(other.Children, ListEquals).Contains(false)) return false; } - - return this.Label == other.Label && this.FormattedNonQubitArgs == other.FormattedNonQubitArgs && - this.IsAdjoint == other.IsAdjoint && this.IsControlled == other.IsControlled && - this.IsMeasurement == other.IsMeasurement && this.IsComposite == other.IsComposite; + + return true; } public override int GetHashCode() { // Stringify qubits, concatenate as string, and get resulting hashcode - var controlsHash = string.Join(",", this.Controls.Select(q => q.ToString())).GetHashCode(); - var targetsHash = string.Join(",", this.Targets.Select(q => q.ToString())).GetHashCode(); + var controlsHash = string.Join(",", this.Controls.Select(q => q?.ToString() ?? "")).GetHashCode(); + var targetsHash = string.Join(",", this.Targets.Select(q => q?.ToString() ?? "")).GetHashCode(); // Recursively get hashcode of inner `RuntimeMetadata` objects, concatenate into a string, // and get resulting hashcode diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 0bcc8a42cd0..7927640a016 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -16,7 +16,7 @@ public class RuntimeMetadataEqualityTests [Fact] public void WrongType() { - RuntimeMetadata a = new RuntimeMetadata { }; + var a = new RuntimeMetadata { }; var i = 5; Assert.False(a.Equals(i)); } @@ -24,10 +24,11 @@ public void WrongType() [Fact] public void NullEquality() { - RuntimeMetadata a = new RuntimeMetadata { }; - Assert.False(a == null); - Assert.False(null == a); - Assert.True(null == null); + var a = new RuntimeMetadata { }; + RuntimeMetadata? b = null; + Assert.NotEqual(a, b); + Assert.NotEqual(b, a); + Assert.Equal(null, null); } [Fact] @@ -57,30 +58,37 @@ public void CheckEquality() Controls = new List() { }, Targets = new List() { }, }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); b.Label = "X"; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.Label = "H"; b.FormattedNonQubitArgs = "(1)"; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.FormattedNonQubitArgs = ""; b.IsAdjoint = true; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.IsAdjoint = false; b.IsControlled = true; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.IsControlled = false; b.IsMeasurement = true; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.IsMeasurement = false; b.IsComposite = true; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); b.IsComposite = false; } @@ -95,13 +103,16 @@ public void ControlsEquality() { Controls = new List() { }, }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); b.Controls = new List() { new FreeQubit(1) }; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); a.Controls = new List() { new FreeQubit(1) }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); } [Fact] @@ -115,13 +126,16 @@ public void TargetsEquality() { Targets = new List() { }, }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); b.Targets = new List() { new FreeQubit(1) }; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); a.Targets = new List() { new FreeQubit(1) }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); } [Fact] @@ -143,23 +157,28 @@ public void ChildrenEquality() new List(), }, }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); var aChildren = a.Children.ToList(); aChildren[0] = new List() { new RuntimeMetadata() { Label = "H" } }; a.Children = aChildren; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); var bChildren = b.Children.ToList(); bChildren[0] = new List() { new RuntimeMetadata() { Label = "X" } }; b.Children = bChildren; - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); bChildren[0] = new List() { new RuntimeMetadata() { Label = "H" } }; - Assert.True(a == b); + Assert.Equal(a, b); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); b.Children = b.Children.SkipLast(1); - Assert.False(a == b); + Assert.NotEqual(a, b); + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); } } @@ -185,10 +204,7 @@ public void CNOT() Targets = new List() { target }, }; - var metadata = op.GetRuntimeMetadata(args); - var equals = metadata == expected; - - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -212,7 +228,7 @@ public void CCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -234,7 +250,7 @@ public void Ry() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -256,7 +272,7 @@ public void M() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } } @@ -281,7 +297,7 @@ public void MResetX() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -303,7 +319,7 @@ public void MResetY() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -325,7 +341,7 @@ public void MResetZ() Targets = new List() { measureQubit }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } } @@ -350,7 +366,7 @@ public void FooUDTOp() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } } @@ -376,7 +392,7 @@ public void ControlledH() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -399,7 +415,7 @@ public void ControlledX() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -423,7 +439,7 @@ public void ControlledCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -449,30 +465,7 @@ public void ControlledCCNOT() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); - } - - [Fact] - public void ControlledUDT() - { - IQArray controls = new QArray(new[] { new FreeQubit(0) }); - Qubit target = new FreeQubit(1); - var op = new QuantumSimulator().Get().Controlled; - var args = new QTuple, Circuits.FooUDT>>((controls, new Circuits.FooUDT(("bar", (target, 2.1))))); - var expected = new RuntimeMetadata() - { - Label = "FooUDTOp", - FormattedNonQubitArgs = "(\"bar\", (2.1))", - IsAdjoint = false, - IsControlled = true, - IsMeasurement = false, - IsComposite = false, - Children = null, - Controls = controls, - Targets = new List() { target }, - }; - - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } } @@ -497,7 +490,7 @@ public void AdjointH() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -519,29 +512,7 @@ public void AdjointX() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); - } - - [Fact] - public void AdjointUDT() - { - Qubit target = new FreeQubit(0); - var op = new QuantumSimulator().Get().Adjoint; - var args = op.__dataIn(new Circuits.FooUDT(("bar", (target, 2.1)))); - var expected = new RuntimeMetadata() - { - Label = "FooUDTOp", - FormattedNonQubitArgs = "(\"bar\", (2.1))", - IsAdjoint = true, - IsControlled = false, - IsMeasurement = false, - IsComposite = false, - Children = null, - Controls = new List() { }, - Targets = new List() { target }, - }; - - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -563,7 +534,7 @@ public void AdjointAdjointH() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -587,8 +558,8 @@ public void ControlledAdjointH() Targets = new List() { target }, }; - Assert.True(op1.GetRuntimeMetadata(args) == expected); - Assert.True(op2.GetRuntimeMetadata(args) == expected); + Assert.Equal(op1.GetRuntimeMetadata(args), expected); + Assert.Equal(op2.GetRuntimeMetadata(args), expected); } [Fact] @@ -613,9 +584,9 @@ public void ControlledAdjointAdjointH() Targets = new List() { target }, }; - Assert.True(op1.GetRuntimeMetadata(args) == expected); - Assert.True(op2.GetRuntimeMetadata(args) == expected); - Assert.True(op3.GetRuntimeMetadata(args) == expected); + Assert.Equal(op1.GetRuntimeMetadata(args), expected); + Assert.Equal(op2.GetRuntimeMetadata(args), expected); + Assert.Equal(op3.GetRuntimeMetadata(args), expected); } } @@ -642,7 +613,7 @@ public void PartialRy() Targets = new List() { target }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } [Fact] @@ -665,7 +636,7 @@ public void PartialUDT() Targets = new List() { }, }; - Assert.True(op.GetRuntimeMetadata(args) == expected); + Assert.Equal(op.GetRuntimeMetadata(args), expected); } } } From 53fa9108819ba5485d4a1f242160459ea551385e Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Wed, 15 Jul 2020 13:27:38 -0400 Subject: [PATCH 09/11] Fix typo --- src/Simulation/Core/RuntimeMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/Core/RuntimeMetadata.cs b/src/Simulation/Core/RuntimeMetadata.cs index decbe223858..9054ce12cc2 100644 --- a/src/Simulation/Core/RuntimeMetadata.cs +++ b/src/Simulation/Core/RuntimeMetadata.cs @@ -44,7 +44,7 @@ public class RuntimeMetadata /// /// /// - /// Currently not used as this is intended for compositeoperations, + /// Currently not used as this is intended for composite operations, /// such as ApplyToEach. /// public bool IsComposite { get; set; } From 53855f51a7028b56bd327bb15554c6378f748939 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Wed, 15 Jul 2020 14:36:15 -0400 Subject: [PATCH 10/11] Remove useless test --- src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs index 7927640a016..5e551565841 100644 --- a/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs +++ b/src/Simulation/Simulators.Tests/RuntimeMetadataTests.cs @@ -28,7 +28,6 @@ public void NullEquality() RuntimeMetadata? b = null; Assert.NotEqual(a, b); Assert.NotEqual(b, a); - Assert.Equal(null, null); } [Fact] From 49a2bbb4399d62b4f3ba27e6e2b3a097557780f1 Mon Sep 17 00:00:00 2001 From: Raphael Koh Date: Wed, 15 Jul 2020 15:47:57 -0400 Subject: [PATCH 11/11] Empty commit to trigger CI build