From c5c87ef21d39f79df4a14de13937c6dc21c12bbe Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Sun, 27 Oct 2019 16:04:53 -0700 Subject: [PATCH 01/17] adding initial version of StackTrace collector with tests --- src/Simulation/Common/StackTrace.cs | 153 ++++++++++++++++++ src/Simulation/Core/Generics/Adjoint.cs | 3 +- src/Simulation/Core/Generics/Controlled.cs | 3 +- .../Core/Generics/GenericPartial.cs | 3 +- src/Simulation/Core/Operations/Adjoint.cs | 3 +- src/Simulation/Core/Operations/Controlled.cs | 3 +- src/Simulation/Core/Operations/Operation.cs | 10 +- .../Core/Operations/OperationPartial.cs | 4 +- .../Simulators.Tests/Circuits/Fail.qs | 33 +++- .../Simulators.Tests/StackTraceTests.cs | 95 +++++++++++ 10 files changed, 301 insertions(+), 9 deletions(-) create mode 100644 src/Simulation/Common/StackTrace.cs create mode 100644 src/Simulation/Simulators.Tests/StackTraceTests.cs diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs new file mode 100644 index 00000000000..648a5d574c5 --- /dev/null +++ b/src/Simulation/Common/StackTrace.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.Common +{ + [Serializable] + public class StackFrame + { + public readonly ICallable operation; + public readonly IApplyData argument; + + /// + /// The path to the source where operation is defined + /// + public string sourceFile; + + /// + /// Line in the operation that resulted in failure. Note that for automatically derived Adjoint and Controlled + /// variants of the operation, the line always points to the operation declaration + /// + public int failedLineNumber; + + public int declarationStartLineNumber; + public int declarationEndLineNumber; + + public StackFrame(ICallable _operation, IApplyData _argument) + { + operation = _operation; + argument = _argument; + sourceFile = null; + failedLineNumber = -1; + declarationStartLineNumber = -1; + declarationEndLineNumber = -1; + } + } + + public class StackTraceCollector + { + private readonly Stack callStack; + private System.Diagnostics.StackFrame[] frames = null; + bool hasNotFailed = true; + + public StackTraceCollector(SimulatorBase sim) + { + sim.OnOperationStart += OnOperationStart; + sim.OnOperationEnd += OnOperationEnd; + sim.OnFail += OnFail; + callStack = new Stack(); + } + + void OnOperationStart(ICallable callable, IApplyData arg) + { + callStack.Push(new StackFrame(callable, arg)); + } + + void OnOperationEnd(ICallable callable, IApplyData arg) + { + if (hasNotFailed) + { + callStack.Pop(); + } + } + + void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo) + { + if (hasNotFailed) + { + hasNotFailed = false; + } + + System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(exceptionInfo.SourceException, 0, true); + System.Diagnostics.StackFrame[] currentFrames = stackTrace.GetFrames(); + + if (frames == null) + { + frames = currentFrames; + } + else + { + // When the exception is thrown, OnFail can be called mutiple times. + // With every next call we see bigger part of the call stack, so we save the biggest call stack + if (currentFrames.Length > frames.Length) + { + frames = currentFrames; + } + } + } + + public static ICallable UnwrapCallable(ICallable op) + { + ICallable res = op; + while (res as IWrappedOperation != null) + { + res = (res as IWrappedOperation).BaseOperation; + } + return res; + } + + static void PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) + { + List> qsharpSourceLocations = new List>(); + foreach (System.Diagnostics.StackFrame csStackFrame in csharpCallStack) + { + string fileName = csStackFrame.GetFileName(); + if (System.IO.Path.GetExtension(fileName) == ".qs") + { + qsharpSourceLocations.Add(new Tuple(fileName, csStackFrame.GetFileLineNumber())); + } + } + + StackFrame[] stackFrames = qsharpCallStack.ToArray(); + for (int i = 0; i < stackFrames.Length; ++i) + { + ICallable op = UnwrapCallable(stackFrames[i].operation); + object[] locations = op.GetType().GetCustomAttributes(typeof(SourceLocationAttribute), true); + foreach (object location in locations) + { + SourceLocationAttribute sourceLocation = (location as SourceLocationAttribute); + if (sourceLocation != null && sourceLocation.SpecializationKind == op.Variant) + { + stackFrames[i].sourceFile = System.IO.Path.GetFullPath(sourceLocation.SourceFile); + stackFrames[i].declarationStartLineNumber = sourceLocation.StartLine; + stackFrames[i].declarationEndLineNumber = sourceLocation.EndLine; + + string fileName = System.IO.Path.GetFullPath(qsharpSourceLocations[i].Item1); + int failedLineNumber = qsharpSourceLocations[i].Item2; + if (fileName == stackFrames[i].sourceFile && + sourceLocation.StartLine <= failedLineNumber && + ((failedLineNumber <= sourceLocation.EndLine) || sourceLocation.EndLine == -1)) + { + stackFrames[i].failedLineNumber = failedLineNumber; + } + } + } + } + } + + public Stack CallStack + { + get + { + PopulateSourceLocations(callStack, frames); + return callStack; + } + } + } +} diff --git a/src/Simulation/Core/Generics/Adjoint.cs b/src/Simulation/Core/Generics/Adjoint.cs index b00116bb7c8..524df1feda1 100644 --- a/src/Simulation/Core/Generics/Adjoint.cs +++ b/src/Simulation/Core/Generics/Adjoint.cs @@ -23,7 +23,7 @@ public interface IAdjointable : ICallable /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericAdjoint.DebuggerProxy))] - public class GenericAdjoint : GenericCallable, IApplyData + public class GenericAdjoint : GenericCallable, IApplyData, IWrappedOperation { public GenericAdjoint(GenericCallable baseOp) : base(baseOp.Factory, null) { @@ -31,6 +31,7 @@ public GenericAdjoint(GenericCallable baseOp) : base(baseOp.Factory, null) } public GenericCallable BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; IEnumerable IApplyData.Qubits => ((IApplyData)this.BaseOp)?.Qubits; diff --git a/src/Simulation/Core/Generics/Controlled.cs b/src/Simulation/Core/Generics/Controlled.cs index 65d5235c0bb..15f57783dfa 100644 --- a/src/Simulation/Core/Generics/Controlled.cs +++ b/src/Simulation/Core/Generics/Controlled.cs @@ -25,7 +25,7 @@ public partial interface IControllable : ICallable /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericControlled.DebuggerProxy))] - public class GenericControlled : GenericCallable, IApplyData + public class GenericControlled : GenericCallable, IApplyData, IWrappedOperation { public GenericControlled(GenericCallable baseOp) : base(baseOp.Factory, null) { @@ -33,6 +33,7 @@ public GenericControlled(GenericCallable baseOp) : base(baseOp.Factory, null) } public GenericCallable BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; IEnumerable IApplyData.Qubits => ((IApplyData)this.BaseOp)?.Qubits; diff --git a/src/Simulation/Core/Generics/GenericPartial.cs b/src/Simulation/Core/Generics/GenericPartial.cs index 295502d7c8f..3d8408d8ceb 100644 --- a/src/Simulation/Core/Generics/GenericPartial.cs +++ b/src/Simulation/Core/Generics/GenericPartial.cs @@ -14,7 +14,7 @@ namespace Microsoft.Quantum.Simulation.Core /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericPartial.DebuggerProxy))] - public class GenericPartial : GenericCallable, IApplyData + public class GenericPartial : GenericCallable, IApplyData, IWrappedOperation { private Lazy __qubits = null; @@ -29,6 +29,7 @@ public GenericPartial(GenericCallable baseOp, object partialValues) : base(baseO } public GenericCallable BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; public override string Name => this.BaseOp.Name; public override string FullName => this.BaseOp.FullName; diff --git a/src/Simulation/Core/Operations/Adjoint.cs b/src/Simulation/Core/Operations/Adjoint.cs index 428858f4c66..20bb62fc5fc 100644 --- a/src/Simulation/Core/Operations/Adjoint.cs +++ b/src/Simulation/Core/Operations/Adjoint.cs @@ -39,7 +39,7 @@ public Adjointable(IOperationFactory m) : base(m) /// Class used to represents an operation that has been adjointed. /// [DebuggerTypeProxy(typeof(AdjointedOperation<,>.DebuggerProxy))] - public class AdjointedOperation : Unitary, IApplyData, ICallable + public class AdjointedOperation : Unitary, IApplyData, ICallable, IWrappedOperation { public AdjointedOperation(Operation op) : base(op.Factory) { @@ -50,6 +50,7 @@ public AdjointedOperation(Operation op) : base(op.Factory) } public Operation BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; public override void Init() { } diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index 2c9f1e183cc..1f7be787f66 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -38,7 +38,7 @@ public Controllable(IOperationFactory m) : base(m) { } /// This class is used to represents an operation that has been controlled. /// [DebuggerTypeProxy(typeof(ControlledOperation<,>.DebuggerProxy))] - public class ControlledOperation : Unitary<(IQArray, I)>, IApplyData, ICallable + public class ControlledOperation : Unitary<(IQArray, I)>, IApplyData, ICallable, IWrappedOperation { public class In : IApplyData { @@ -66,6 +66,7 @@ public ControlledOperation(Operation op) : base(op.Factory) } public Operation BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; public override void Init() { } diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 7963654f389..2349b738c88 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -17,7 +17,15 @@ public partial interface ICallable : ICallable ICallable Partial

(Func mapper); } - + ///

+ /// An operation that wrapps another operation, for example + /// , , + /// , + /// + public interface IWrappedOperation + { + ICallable BaseOperation { get; } + } /// /// The base class for all ClosedType quantum operations. diff --git a/src/Simulation/Core/Operations/OperationPartial.cs b/src/Simulation/Core/Operations/OperationPartial.cs index 4b059962132..46b2407b616 100644 --- a/src/Simulation/Core/Operations/OperationPartial.cs +++ b/src/Simulation/Core/Operations/OperationPartial.cs @@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Simulation.Core /// Optionally it can receive a Mapper to do the same. /// [DebuggerTypeProxy(typeof(OperationPartial<,,>.DebuggerProxy))] - public class OperationPartial : Operation, IUnitary

+ public class OperationPartial : Operation, IUnitary

, IWrappedOperation { private Lazy __qubits = null; @@ -59,6 +59,7 @@ public OperationPartial(Operation op, object partialTuple) : base(op.Facto public override void Init() { } public Operation BaseOp { get; } + ICallable IWrappedOperation.BaseOperation => BaseOp; public Func Mapper { get; } @@ -137,6 +138,7 @@ ICallable ICallable.Partial(Func mapper) IUnitary

IUnitary

.Adjoint => base.Adjoint; IUnitary<(IQArray, P)> IUnitary

.Controlled => base.Controlled; + IUnitary IUnitary

.Partial(Func mapper) => new OperationPartial(this, mapper); public override string ToString() => $"{this.BaseOp}{{_}}"; diff --git a/src/Simulation/Simulators.Tests/Circuits/Fail.qs b/src/Simulation/Simulators.Tests/Circuits/Fail.qs index 3fb9302255c..0188a3ca41f 100644 --- a/src/Simulation/Simulators.Tests/Circuits/Fail.qs +++ b/src/Simulation/Simulators.Tests/Circuits/Fail.qs @@ -3,10 +3,39 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { - operation AlwaysFail() : Unit { + operation AlwaysFail() : Unit is Adj + Ctl { fail "Always fail"; } -} + operation AlwaysFail1() : Unit is Adj + Ctl{ + AlwaysFail(); + } + operation AlwaysFail2() : Unit is Adj + Ctl { + Controlled AlwaysFail1(new Qubit[0],()); + } + operation AlwaysFail3() : Unit is Adj + Ctl { + Adjoint AlwaysFail2(); + } + operation AlwaysFail4() : Unit is Adj + Ctl { + Adjoint AlwaysFail3(); + } + operation GenericFail<'T,'U>( a : 'T, b : 'U ) : Unit is Adj + Ctl { + AlwaysFail(); + } + + operation GenericFail1() : Unit is Adj + Ctl { + GenericFail(5,6); + } + + operation PartialFail( a : Int, b : Int ) : Unit is Adj + Ctl { + AlwaysFail(); + } + + operation PartialFail1() : Unit is Adj + Ctl { + let op = PartialFail(0,_); + op(2); + } + +} \ No newline at end of file diff --git a/src/Simulation/Simulators.Tests/StackTraceTests.cs b/src/Simulation/Simulators.Tests/StackTraceTests.cs new file mode 100644 index 00000000000..4e3d6850b80 --- /dev/null +++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +using System; +using System.Threading.Tasks; + +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Simulators.Tests.Circuits; +using Microsoft.Quantum.Simulation.Simulators.Exceptions; +using Xunit.Abstractions; + +namespace Microsoft.Quantum.Simulation.Simulators.Tests +{ + public class StackTraceTests + { + const string namespacePrefix = "Microsoft.Quantum.Simulation.Simulators.Tests.Circuits."; + + private readonly ITestOutputHelper output; + public StackTraceTests(ITestOutputHelper output) + { + this.output = output; + } + + [Fact] + public void AlwaysFail4Test() + { + ToffoliSimulator sim = new ToffoliSimulator(); + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(5, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "AlwaysFail1", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "AlwaysFail2", stackFrames[2].operation.FullName); + Assert.Equal(namespacePrefix + "AlwaysFail3", stackFrames[3].operation.FullName); + Assert.Equal(namespacePrefix + "AlwaysFail4", stackFrames[4].operation.FullName); + + Assert.Equal(OperationFunctor.Controlled, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Controlled, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + Assert.Equal(OperationFunctor.Adjoint, stackFrames[3].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[4].operation.Variant); + + Assert.Equal(14, stackFrames[2].failedLineNumber); + Assert.Equal(21, stackFrames[4].failedLineNumber); + + // For Adjoint and Controlled we expect failedLineNumber to be equal to declarationStartLineNumber + Assert.Equal(stackFrames[0].declarationStartLineNumber, stackFrames[0].failedLineNumber); + Assert.Equal(stackFrames[1].declarationStartLineNumber, stackFrames[1].failedLineNumber); + Assert.Equal(stackFrames[3].declarationStartLineNumber, stackFrames[3].failedLineNumber); + } + } + + [Fact] + public void GenericFail1Test() + { + ToffoliSimulator sim = new ToffoliSimulator(); + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Body, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(7, stackFrames[0].failedLineNumber); + Assert.Equal(25, stackFrames[1].failedLineNumber); + Assert.Equal(29, stackFrames[2].failedLineNumber); + } + } + } +} \ No newline at end of file From 07b8ff567a67198ab247c47f24931f04857ab342 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Sun, 27 Oct 2019 21:00:18 -0700 Subject: [PATCH 02/17] adding more tests --- .../Simulators.Tests/Circuits/Fail.qs | 17 ++ .../Simulators.Tests/StackTraceTests.cs | 176 ++++++++++++++++-- 2 files changed, 177 insertions(+), 16 deletions(-) diff --git a/src/Simulation/Simulators.Tests/Circuits/Fail.qs b/src/Simulation/Simulators.Tests/Circuits/Fail.qs index 0188a3ca41f..5ecd7552afd 100644 --- a/src/Simulation/Simulators.Tests/Circuits/Fail.qs +++ b/src/Simulation/Simulators.Tests/Circuits/Fail.qs @@ -38,4 +38,21 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { op(2); } + operation PartialAdjFail1() : Unit is Adj + Ctl { + let op = PartialFail(0,_); + Adjoint op(2); + } + + operation PartialCtlFail1() : Unit is Adj + Ctl { + let op = PartialFail(0,_); + Controlled op(new Qubit[0], 2); + } + + operation GenericAdjFail1() : Unit is Adj + Ctl { + Adjoint GenericFail(5,6); + } + + operation GenericCtlFail1() : Unit is Adj + Ctl { + Controlled GenericFail( new Qubit[0], (5,6)); + } } \ No newline at end of file diff --git a/src/Simulation/Simulators.Tests/StackTraceTests.cs b/src/Simulation/Simulators.Tests/StackTraceTests.cs index 4e3d6850b80..851bae4e0e7 100644 --- a/src/Simulation/Simulators.Tests/StackTraceTests.cs +++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs @@ -66,29 +66,173 @@ public void AlwaysFail4Test() public void GenericFail1Test() { ToffoliSimulator sim = new ToffoliSimulator(); - StackTraceCollector sc = new StackTraceCollector(sim); - ICallable op = sim.Get(); - try + { - QVoid res = op.Apply(QVoid.Instance); + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Body, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(7, stackFrames[0].failedLineNumber); + Assert.Equal(25, stackFrames[1].failedLineNumber); + Assert.Equal(29, stackFrames[2].failedLineNumber); + } } - catch (ExecutionFailException) + { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "GenericAdjFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Adjoint, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Adjoint, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(5, stackFrames[0].failedLineNumber); + Assert.Equal(23, stackFrames[1].failedLineNumber); + Assert.Equal(52, stackFrames[2].failedLineNumber); + } + } + + { + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "GenericFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "GenericCtlFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Controlled, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Controlled, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(5, stackFrames[0].failedLineNumber); + Assert.Equal(23, stackFrames[1].failedLineNumber); + Assert.Equal(56, stackFrames[2].failedLineNumber); + } + } + } - Assert.Equal(3, stackFrames.Length); + [Fact] + public void PartialFail1Test() + { + ToffoliSimulator sim = new ToffoliSimulator(); - Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); - Assert.Equal(namespacePrefix + "GenericFail", stackFrames[1].operation.FullName); - Assert.Equal(namespacePrefix + "GenericFail1", stackFrames[2].operation.FullName); + { + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "PartialFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "PartialFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Body, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(7, stackFrames[0].failedLineNumber); + Assert.Equal(33, stackFrames[1].failedLineNumber); + Assert.Equal(38, stackFrames[2].failedLineNumber); + } + } - Assert.Equal(OperationFunctor.Body, stackFrames[0].operation.Variant); - Assert.Equal(OperationFunctor.Body, stackFrames[1].operation.Variant); - Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + { + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "PartialFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "PartialAdjFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Adjoint, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Adjoint, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(5, stackFrames[0].failedLineNumber); + Assert.Equal(31, stackFrames[1].failedLineNumber); + Assert.Equal(43, stackFrames[2].failedLineNumber); + } + } - Assert.Equal(7, stackFrames[0].failedLineNumber); - Assert.Equal(25, stackFrames[1].failedLineNumber); - Assert.Equal(29, stackFrames[2].failedLineNumber); + { + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack.ToArray(); + + Assert.Equal(3, stackFrames.Length); + + Assert.Equal(namespacePrefix + "AlwaysFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "PartialFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "PartialCtlFail1", stackFrames[2].operation.FullName); + + Assert.Equal(OperationFunctor.Controlled, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Controlled, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + + Assert.Equal(5, stackFrames[0].failedLineNumber); + Assert.Equal(31, stackFrames[1].failedLineNumber); + Assert.Equal(48, stackFrames[2].failedLineNumber); + } } } } From db21e9fcaf337de97be8092a555664d916649ea5 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Sun, 27 Oct 2019 21:14:10 -0700 Subject: [PATCH 03/17] adding placeholders; work in progress --- src/Simulation/Common/StackTrace.cs | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index 648a5d574c5..6e4f2f5d5d8 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -38,6 +38,40 @@ public StackFrame(ICallable _operation, IApplyData _argument) declarationStartLineNumber = -1; declarationEndLineNumber = -1; } + + public string GetOperationSourceFromPDB() + { + string result = null; + try + { + //TODO: + } + catch ( Exception ) + { + + } + return result; + } + + public string GetURLFromPDB() + { + string result = null; + try + { + //TODO: + } + catch (Exception) + { + + } + return result; + } + + public override string ToString() + { + //TODO: + return base.ToString(); + } } public class StackTraceCollector From 3af694e9d6679a4124e9923f1eae2ed0c77f94b6 Mon Sep 17 00:00:00 2001 From: Vadym Date: Mon, 28 Oct 2019 17:28:45 -0700 Subject: [PATCH 04/17] work in progress --- src/Simulation/Common/StackTrace.cs | 31 +++++++++++++------ src/Simulation/Core/Operations/Operation.cs | 2 +- .../Simulators.Tests/Circuits/Fail.qs | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index 6e4f2f5d5d8..c32c5f7296f 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Text; using Microsoft.Quantum.Simulation.Core; +using System.Diagnostics; namespace Microsoft.Quantum.Simulation.Common { @@ -21,12 +22,20 @@ public class StackFrame public string sourceFile; ///

- /// Line in the operation that resulted in failure. Note that for automatically derived Adjoint and Controlled + /// One based line number in the operation that resulted in failure. Note that for automatically derived Adjoint and Controlled /// variants of the operation, the line always points to the operation declaration /// public int failedLineNumber; + /// + /// One based line number where the declaration starts. + /// public int declarationStartLineNumber; + + /// + /// One based line number of the first line after the declaration. + /// The value -1, if the declaration ends on the last line of the file. + /// public int declarationEndLineNumber; public StackFrame(ICallable _operation, IApplyData _argument) @@ -46,7 +55,7 @@ public string GetOperationSourceFromPDB() { //TODO: } - catch ( Exception ) + catch (Exception) { } @@ -78,13 +87,13 @@ public class StackTraceCollector { private readonly Stack callStack; private System.Diagnostics.StackFrame[] frames = null; - bool hasNotFailed = true; + bool hasFailed = false; public StackTraceCollector(SimulatorBase sim) { - sim.OnOperationStart += OnOperationStart; - sim.OnOperationEnd += OnOperationEnd; - sim.OnFail += OnFail; + sim.OnOperationStart += this.OnOperationStart; + sim.OnOperationEnd += this.OnOperationEnd; + sim.OnFail += this.OnFail; callStack = new Stack(); } @@ -95,7 +104,7 @@ void OnOperationStart(ICallable callable, IApplyData arg) void OnOperationEnd(ICallable callable, IApplyData arg) { - if (hasNotFailed) + if (!hasFailed) { callStack.Pop(); } @@ -103,9 +112,9 @@ void OnOperationEnd(ICallable callable, IApplyData arg) void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo) { - if (hasNotFailed) + if (!hasFailed) { - hasNotFailed = false; + hasFailed = true; } System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(exceptionInfo.SourceException, 0, true); @@ -117,10 +126,11 @@ void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo } else { - // When the exception is thrown, OnFail can be called mutiple times. + // When the exception is thrown, OnFail can be called multiple times. // With every next call we see bigger part of the call stack, so we save the biggest call stack if (currentFrames.Length > frames.Length) { + Debug.Assert((frames.Length == 0) || (frames[0].ToString() == currentFrames[0].ToString())); frames = currentFrames; } } @@ -138,6 +148,7 @@ public static ICallable UnwrapCallable(ICallable op) static void PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) { + // TODO: change logic to check if given location in the known Q# call-stack locations List> qsharpSourceLocations = new List>(); foreach (System.Diagnostics.StackFrame csStackFrame in csharpCallStack) { diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index 2349b738c88..c654dc6b299 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -18,7 +18,7 @@ public partial interface ICallable : ICallable } /// - /// An operation that wrapps another operation, for example + /// An operation that wraps another operation, for example /// , , /// , /// diff --git a/src/Simulation/Simulators.Tests/Circuits/Fail.qs b/src/Simulation/Simulators.Tests/Circuits/Fail.qs index 5ecd7552afd..834ef2f4af9 100644 --- a/src/Simulation/Simulators.Tests/Circuits/Fail.qs +++ b/src/Simulation/Simulators.Tests/Circuits/Fail.qs @@ -3,7 +3,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { - operation AlwaysFail() : Unit is Adj + Ctl { + function AlwaysFail() : Unit { fail "Always fail"; } From 24350c5f5c84d1026f57aa73865707118a06fff0 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Mon, 28 Oct 2019 21:55:05 -0700 Subject: [PATCH 05/17] wip --- src/Simulation/Common/StackTrace.cs | 112 ++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index c32c5f7296f..5eead854b85 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -7,6 +7,7 @@ using System.Text; using Microsoft.Quantum.Simulation.Core; using System.Diagnostics; +using System.Linq; namespace Microsoft.Quantum.Simulation.Common { @@ -78,8 +79,8 @@ public string GetURLFromPDB() public override string ToString() { - //TODO: - return base.ToString(); + string location = GetURLFromPDB() ?? $"{sourceFile}:line {failedLineNumber}"; + return $"in {operation.FullName} on {location}"; } } @@ -146,40 +147,107 @@ public static ICallable UnwrapCallable(ICallable op) return res; } - static void PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) + class HalfOpenInterval : IEquatable { - // TODO: change logic to check if given location in the known Q# call-stack locations - List> qsharpSourceLocations = new List>(); - foreach (System.Diagnostics.StackFrame csStackFrame in csharpCallStack) + public readonly int start; + public readonly int end; + + public HalfOpenInterval(int start, int end) + { + if( start > end ) throw new ArgumentException($"Interval start:{start} must be less or equal to end:{end}."); + this.start = start; + this.end = end; + } + + public override bool Equals(object obj) + { + return Equals(obj as HalfOpenInterval); + } + + public bool Equals(HalfOpenInterval other) + { + return other != null && + start == other.start && + end == other.end; + } + + public override int GetHashCode() + { + return HashCode.Combine(start, end); + } + } + + class NonOverlappingHalfOpenIntervalSet + { + class NonOverlappinIntervalsComparator : IComparer { - string fileName = csStackFrame.GetFileName(); - if (System.IO.Path.GetExtension(fileName) == ".qs") + public int Compare(HalfOpenInterval x, HalfOpenInterval y) { - qsharpSourceLocations.Add(new Tuple(fileName, csStackFrame.GetFileLineNumber())); + if (x.end <= y.start) return -1; + if (x.start >= y.end) return 1; + if (x.start == y.start && x.end == y.end) return 0; + throw new ArgumentException("Compared intervals must be non-overlapping"); } } - StackFrame[] stackFrames = qsharpCallStack.ToArray(); - for (int i = 0; i < stackFrames.Length; ++i) + public NonOverlappingHalfOpenIntervalSet(IEnumerable inervals) + { + throw new NotImplementedException(); + } + + public bool Contains(int value) + { + throw new NotImplementedException(); + } + } + + static void PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) + { + // TODO: change logic to check if given location in the known Q# call-stack locations + //List> qsharpSourceLocations = new List>(); + //foreach (System.Diagnostics.StackFrame csStackFrame in csharpCallStack) + //{ + // string fileName = csStackFrame.GetFileName(); + // if (System.IO.Path.GetExtension(fileName) == ".qs") + // { + // qsharpSourceLocations.Add(new Tuple(fileName, csStackFrame.GetFileLineNumber())); + // } + //} + + //string fileName = System.IO.Path.GetFullPath(qsharpSourceLocations[i].Item1); + //int failedLineNumber = qsharpSourceLocations[i].Item2; + //if (fileName == stackFrames[i].sourceFile && + // sourceLocation.StartLine <= failedLineNumber && + // ((failedLineNumber <= sourceLocation.EndLine) || sourceLocation.EndLine == -1)) + //{ + // stackFrames[i].failedLineNumber = failedLineNumber; + //} + + Dictionary> sourceLocations = new Dictionary>(); + foreach (StackFrame currentFrame in qsharpCallStack ) { - ICallable op = UnwrapCallable(stackFrames[i].operation); + ICallable op = UnwrapCallable(currentFrame.operation); object[] locations = op.GetType().GetCustomAttributes(typeof(SourceLocationAttribute), true); foreach (object location in locations) { SourceLocationAttribute sourceLocation = (location as SourceLocationAttribute); if (sourceLocation != null && sourceLocation.SpecializationKind == op.Variant) { - stackFrames[i].sourceFile = System.IO.Path.GetFullPath(sourceLocation.SourceFile); - stackFrames[i].declarationStartLineNumber = sourceLocation.StartLine; - stackFrames[i].declarationEndLineNumber = sourceLocation.EndLine; - - string fileName = System.IO.Path.GetFullPath(qsharpSourceLocations[i].Item1); - int failedLineNumber = qsharpSourceLocations[i].Item2; - if (fileName == stackFrames[i].sourceFile && - sourceLocation.StartLine <= failedLineNumber && - ((failedLineNumber <= sourceLocation.EndLine) || sourceLocation.EndLine == -1)) + currentFrame.sourceFile = System.IO.Path.GetFullPath(sourceLocation.SourceFile); + currentFrame.declarationStartLineNumber = sourceLocation.StartLine + 1; // note that attribute has base 0 line numbers + currentFrame.declarationEndLineNumber = sourceLocation.EndLine == -1 ? -1 : sourceLocation.EndLine + 1; + + List intervals = sourceLocations.GetValueOrDefault(currentFrame.sourceFile); + HalfOpenInterval currentRange = new HalfOpenInterval( + currentFrame.declarationStartLineNumber, + currentFrame.declarationEndLineNumber == -1 ? int.MaxValue : currentFrame.declarationEndLineNumber); + if (intervals == null) + { + sourceLocations.Add(currentFrame.sourceFile, new List(Enumerable.Repeat(currentRange,1)); + } + else { - stackFrames[i].failedLineNumber = failedLineNumber; + intervals.Add(currentRange); } } } From 9ea4108ff11898316c2d8d43c444d148c8ebac7b Mon Sep 17 00:00:00 2001 From: alexva Date: Tue, 29 Oct 2019 14:58:12 -0700 Subject: [PATCH 06/17] QuantumExecutor interface. --- src/Simulation/Common/IQuantumExecutor.cs | 568 ++++++++++++++++++ src/Simulation/Common/Utils.cs | 66 ++ .../Simulators/QuantumExecutor/Allocate.cs | 29 + .../Simulators/QuantumExecutor/Assert.cs | 41 ++ .../Simulators/QuantumExecutor/AssertProb.cs | 43 ++ .../Simulators/QuantumExecutor/Borrow.cs | 29 + .../QuantumExecutor/ClassicalControl.cs | 116 ++++ .../QuantumExecutor/ClassicalControl.qs | 124 ++++ .../Simulators/QuantumExecutor/Dump.cs | 67 +++ .../QuantumExecutor/EmptyQuantumExecutor.cs | 231 +++++++ .../Simulators/QuantumExecutor/Exp.cs | 62 ++ .../Simulators/QuantumExecutor/ExpFrac.cs | 65 ++ .../Simulators/QuantumExecutor/H.cs | 36 ++ .../Simulators/QuantumExecutor/M.cs | 26 + .../Simulators/QuantumExecutor/Measure.cs | 35 ++ .../QuantumExecutorSimulator.cs | 46 ++ .../Simulators/QuantumExecutor/R.cs | 54 ++ .../Simulators/QuantumExecutor/R1.cs | 51 ++ .../Simulators/QuantumExecutor/R1Frac.cs | 53 ++ .../Simulators/QuantumExecutor/RFrac.cs | 56 ++ .../Simulators/QuantumExecutor/Release.cs | 27 + .../Simulators/QuantumExecutor/Reset.cs | 27 + .../Simulators/QuantumExecutor/Return.cs | 27 + .../Simulators/QuantumExecutor/S.cs | 49 ++ .../Simulators/QuantumExecutor/SWAP.cs | 35 ++ .../Simulators/QuantumExecutor/T.cs | 52 ++ .../Simulators/QuantumExecutor/X.cs | 35 ++ .../Simulators/QuantumExecutor/Y.cs | 35 ++ .../Simulators/QuantumExecutor/Z.cs | 35 ++ .../Simulators/QuantumExecutor/random.cs | 52 ++ 30 files changed, 2172 insertions(+) create mode 100644 src/Simulation/Common/IQuantumExecutor.cs create mode 100644 src/Simulation/Common/Utils.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Allocate.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Assert.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/AssertProb.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Borrow.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Dump.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Exp.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/H.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/M.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Measure.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/R.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/R1.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/R1Frac.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/RFrac.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Release.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Reset.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Return.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/S.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/SWAP.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/T.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/X.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Y.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/Z.cs create mode 100644 src/Simulation/Simulators/QuantumExecutor/random.cs diff --git a/src/Simulation/Common/IQuantumExecutor.cs b/src/Simulation/Common/IQuantumExecutor.cs new file mode 100644 index 00000000000..935a217ed75 --- /dev/null +++ b/src/Simulation/Common/IQuantumExecutor.cs @@ -0,0 +1,568 @@ +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + /// + /// An interface for implementing QDK target machines which work + /// on a quantum circuit level. + /// It is intended to be used with . + /// + /// + /// Simulators implemented using interface do not manage qubits on their own. + /// Instead they are notified when qubits are allocated, released, borrowed and returned. + /// + public interface IQuantumExecutor + { + /// + /// Called when Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to . + /// + /// + /// When adjoint of R is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R(Pauli axis, double theta, Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to controlled on . + /// + /// + /// When adjoint of Controlled R is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . + /// + /// + /// When adjoint of RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void RFrac(Pauli axis, long numerator, long power, Qubit qubit); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . + /// + /// + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to . + /// + /// + /// When adjoint of Exp is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void Exp(IQArray paulis, double theta, IQArray qubits); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to controlled on . + /// + /// + /// When adjoint of Controlled Exp is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . + /// + /// + /// When adjoint of ExpFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . + /// + /// + /// When adjoint of Controlled ExpFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.H is called in Q#. + /// In Q# the operation applies Hadamard gate to . The gate is given by matrix H=((1,1),(1,-1))/√2. + /// + /// + /// When adjoint of H is called in Q#, is called because Hadamard is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void H(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.H is called in Q#. + /// In Q# the operation applies Hadamard gate to controlled on . The gate is given by matrix H=((1,1),(1,-1))/√2. + /// + /// + /// When adjoint of Controlled H is called in Q#, is called because Hadamard is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledH(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.S is called in Q#. + /// In Q# the operation applies S gate to . The gate is given by matrix S=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void S(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.S is called in Q#. + /// In Q# the operation applies S gate to controlled on . The gate is given by matrix S=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of Controlled S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledS(IQArray controls, Qubit qubit); + + /// + /// Called when adjoint Microsoft.Quantum.Intrinsic.S is called in Q#. + /// In Q# the operation applies S† gate to . The gate is given by matrix S†=((1,0),(0,-𝑖)). + /// + /// + /// When adjoint of Adjoint S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void SAdj(Qubit qubit); + + /// + /// Called when controlled adjoint Microsoft.Quantum.Intrinsic.S is called in Q#. + /// In Q# the operation applies S† gate to controlled on . The gate is given by matrix S†=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of Controlled S† is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledSAdj(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.T is called in Q#. + /// In Q# the operation applies T gate to . The gate is given by matrix T=((1,0),(0,𝑒𝑥𝑝(𝑖⋅π/4))). + /// + /// + /// When adjoint of T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void T(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.T is called in Q#. + /// In Q# the operation applies T gate to controlled on . The gate is given by matrix T=((1,0),(0,𝑒𝑥𝑝(𝑖⋅π/4))). + /// + /// + /// When adjoint of Controlled T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledT(IQArray controls, Qubit qubit); + + /// + /// Called when adjoint Microsoft.Quantum.Intrinsic.T is called in Q#. + /// In Q# the operation applies T† gate to . The gate is given by matrix T†=((1,0),(0,𝑒𝑥𝑝(-𝑖⋅π/4))). + /// + /// + /// When adjoint of Adjoint T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void TAdj(Qubit qubit); + + /// + /// Called when controlled adjoint Microsoft.Quantum.Intrinsic.T is called in Q#. + /// In Q# the operation applies T† gate to controlled on . The gate is given by matrix T†=((1,0),(0,𝑒𝑥𝑝(-𝑖⋅π/4))). + /// + /// + /// When adjoint of Controlled T† is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledTAdj(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.M is called in Q#. + /// In Q# the operation measures in Z basis, in other words in the computational basis. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . + /// + /// Qubit to which the gate should be applied. + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result M(Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Measure is called in Q#. + /// In Q# the operation measures multi-qubit Pauli observable given by on . + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . + /// + /// Qubits to which the gate should be applied. + /// Array of single-qubit Pauli values describing multi-qubit Pauli observable. + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result Measure(IQArray bases, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Reset is called in Q#. + /// In Q# the operation, measures and ensures it is in the |0⟩ state such that it can be safely released. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Reset(Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The expected result of Measure(bases, qubits) + /// A message to be reported if the assertion fails. + void Assert(IQArray bases, IQArray qubits, Result result, string msg); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// + /// + /// The names and the order of the parameters is similar to the corresponding Q# operation./ + /// + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The probability with which result Zero is expected. + /// A message to be reported if the assertion fails. + /// The precision with which the probability of Zero outcome is specified. + void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol); + + /// + /// Called when Microsoft.Quantum.Intrinsic.X is called in Q#. + /// In Q# the operation applies X gate to . The gate is given by matrix X=((0,1),(1,0)). + /// + /// + /// When adjoint of X is called in Q#, is called because X is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void X(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.X is called in Q#. + /// In Q# the operation applies X gate to controlled on . The gate is given by matrix X=((0,1),(1,0)). + /// + /// + /// When adjoint of Controlled X is called in Q#, is called because X is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledX(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// In Q# the operation applies Y gate to . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// + /// + /// When adjoint of Y is called in Q#, is called because Y is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Y(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// In Q# the operation applies X gate to controlled on . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// + /// + /// When adjoint of Controlled Y is called in Q#, is called because Y is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledY(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// In Q# the operation applies Z gate to . The gate is given by matrix Z=((1,0),(0,-1)). + /// + /// + /// When adjoint of Z is called in Q#, is called because Z is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Z(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// In Q# the operation applies Z gate to controlled on . The gate is given by matrix Z=((1,0),(0,-1)). + /// + /// + /// When adjoint of Controlled Z is called in Q#, is called because Z is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledZ(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.R1 is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to . + /// + /// + /// When adjoint of R1 is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R1(double theta, Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to controlled on . + /// + /// + /// When adjoint of Controlled R1 is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR1(IQArray controls, double theta, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to . + /// + /// + /// When adjoint of R1Frac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R1Frac(long numerator, long power, Qubit qubit); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to controlled on . + /// + /// + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states. + /// + /// + /// When adjoint of SWAP is called in Q#, is called because SWAP is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// First qubit to be swapped. + /// Second qubit to be swapped. + void SWAP(Qubit qubit1, Qubit qubit2); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states controlled on . + /// + /// + /// When adjoint of Controlled SWAP is called in Q#, is called because SWAP is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// First qubit to be swapped. + /// Second qubit to be swapped. + void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2); + + /// + /// Called before a call to any Q# operation. + /// + /// Information about operation being called. + /// Information about the arguments passed to the operation. + /// + /// To get the fully qualified Q# name of operation being called use . + /// For the variant of operation, that is to find if Adjoint, Controlled or Controlled Adjoint being called use . + /// To get a sequence of all qubits passed to the operation use . + /// + void OnOperationStart(ICallable operation, IApplyData arguments); + + /// + /// Called when returning from a call to any Q# operation. + /// + /// Information about operation being called. + /// Information about the arguments passed to the operation. + /// + /// To get the fully qualified Q# name of operation being called use . + /// For the variant of operation, that is to find if Adjoint, Controlled or Controlled Adjoint being called use . + /// To get a sequence of all qubits passed to the operation use . + /// + void OnOperationEnd(ICallable operation, IApplyData arguments); + + /// + /// Called in the end of the call to any Q# operation. + /// + /// Information about exception that was raised. + /// + /// + void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo); + + /// + /// Intended for a limited support of branching upon measurement results on a simulator level. + /// + /// The result of the measurement upon which branching is to be performed. + /// Corresponds to quantum program that must be executed if result is + /// Corresponds to quantum program that must be executed if result is + /// + /// Calling onZero() will result in the execution of quantum program that Q# user intends to execute if result is . + /// The program is executed with the same instance of interface. + /// + void ClassicallyControlled(Result measurementResult, Action onZero, Action onOne); + + /// + /// Called when qubits are allocated by Q# using block. + /// + /// Qubits that are allocated. + /// + /// Every qubit in simulation framework has a unique identifier . + /// All newly allocated qubits are in |0⟩ state. + /// + void OnAllocateQubits(IQArray qubits); + + /// + /// Called when qubits are released in Q# in the end of using block. + /// + /// Qubits that are released. + /// + /// Every qubit in simulation framework has a unique identifier . + /// All qubits are expected to be released in |0⟩ state. + /// + void OnReleaseQubits(IQArray qubits); + + /// + /// Called when qubits are borrowed by Q# borrowing block. + /// + /// Qubits that are borrowed. + /// + /// Every qubit in simulation framework has a unique identifier . + /// Borrowed qubits can be in any state. + /// + void OnBorrowQubits(IQArray qubits); + + /// + /// Called when qubits are returned in the end of Q# borrowing block. + /// + /// Qubits that has been allocated. + /// + /// Every qubit in simulation framework has a unique identifier . + /// Borrowed qubits are expected to be returned in the same state as the state they have been borrowed in. + /// + void OnReturnQubits(IQArray qubits); + + /// + /// Called when + /// Microsoft.Quantum.Diagnostics.DumpMachine + /// is called in Q#. + /// + /// + /// The names and the order of the parameters are similar to corresponding Q# operation. + /// + /// + /// Provides information on where to generate the DumpMachine state. + void OnDumpMachine(T location); + + /// + /// Called when + /// Microsoft.Quantum.Diagnostics.DumpRegister + /// is called in Q#. + /// + /// + /// The names and the order of the parameters are similar to corresponding Q# operation. + /// + /// + /// Provides information on where to generate the DumpRegister state. + /// The list of qubits to report. + void OnDumpRegister(T location, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Message is called in Q#. + /// + /// + /// The names and the order of the parameters are the same as corresponding Q# operations. + /// + /// The message to be reported. + void OnMessage(string msg); + } +} diff --git a/src/Simulation/Common/Utils.cs b/src/Simulation/Common/Utils.cs new file mode 100644 index 00000000000..6850ad7975d --- /dev/null +++ b/src/Simulation/Common/Utils.cs @@ -0,0 +1,66 @@ +using Microsoft.Quantum.Intrinsic; +using Microsoft.Quantum.Simulation.Core; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Quantum.Simulation.Common +{ + public class CommonUtils + { + /// + /// Removes PauliI terms from observable and corresponding qubits from qubits. + /// Returns the observable description that is equivalent to the original one, but has no PauliI terms + /// + public static void PruneObservable(IQArray observable, IQArray qubits, out QArray prunnedObservable, out QArray prunnedQubits) + { + Debug.Assert(observable != null); + Debug.Assert(qubits != null); + Debug.Assert(observable.Length == qubits.Length); + prunnedObservable = new QArray(PrunnedSequence(observable, Pauli.PauliI, observable)); + prunnedQubits = new QArray(PrunnedSequence(observable, Pauli.PauliI, qubits)); + } + + /// + /// Returns IEnumerable that contains sub-sequence of [i], such that [i] is not equal to . + /// + public static IEnumerable PrunnedSequence(IQArray sequence, U value, IQArray sequenceToPrune ) + { + for (uint i = 0; i < sequence.Length; ++i) + { + if (!sequence[i].Equals(value)) + { + yield return sequenceToPrune[i]; + } + } + } + + /// + /// Converts numbers of the form /2^ into canonical form where is odd or zero. + /// If is zero, must also be zero in the canonical form. + /// + public static (long, long) Reduce(long numerator, long denominatorPower) + { + if (numerator == 0) + { + return (0, 0); + } + + if (numerator % 2 != 0) + { + return (numerator, denominatorPower); + } + + long numNew = numerator; + long denomPowerNew = denominatorPower; + + while (numNew % 2 == 0) + { + numNew /= 2; + denomPowerNew -= 1; + } + + return (numNew, denomPowerNew); + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Allocate.cs b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs new file mode 100644 index 00000000000..5f8c9c336ac --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs @@ -0,0 +1,29 @@ +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimAllocate : Intrinsic.Allocate + { + private readonly QuantumExecutorSimulator sim; + public QuantumExecutorSimAllocate(QuantumExecutorSimulator m) : base(m){ + sim = m; + } + + public override Qubit Apply() + { + IQArray qubits = sim.QubitManager.Allocate(1); + sim.QuantumExecutor.OnAllocateQubits(qubits); + return qubits[0]; + } + + public override IQArray Apply( long count ) + { + IQArray qubits = sim.QubitManager.Allocate(count); + sim.QuantumExecutor.OnAllocateQubits(qubits); + return qubits; + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumExecutor/Assert.cs b/src/Simulation/Simulators/QuantumExecutor/Assert.cs new file mode 100644 index 00000000000..fef0b748262 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Assert.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimAssert : Quantum.Intrinsic.Assert + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimAssert(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray, Result, string), QVoid> Body => (_args) => + { + var (paulis, qubits, result, msg) = _args; + if (paulis.Length != qubits.Length) + { + IgnorableAssert.Assert((paulis.Length != qubits.Length), "Arrays length mismatch"); + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumExecutor.Assert(newPaulis, newQubits, result, msg); + + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, Result, string), QVoid> AdjointBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, string)), QVoid> ControlledBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, string)), QVoid> ControlledAdjointBody => (_args) => { return QVoid.Instance; }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs b/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs new file mode 100644 index 00000000000..da8446aa8c8 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimAssertProb : Quantum.Intrinsic.AssertProb + { + + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimAssertProb(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray, Result, double, string, double), QVoid> Body => (_args) => + { + var (paulis, qubits, result, expectedPr, msg, tol) = _args; + if (paulis.Length != qubits.Length) + { + IgnorableAssert.Assert((paulis.Length != qubits.Length), "Arrays length mismatch"); + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + double probabilityOfZero = result == Result.Zero ? expectedPr : 1.0 - expectedPr; + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumExecutor.AssertProb(newPaulis, newQubits, probabilityOfZero, msg, tol ); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, Result, double, string, double), QVoid> AdjointBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, double, string, double)), QVoid> ControlledBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, double, string, double)), QVoid> ControlledAdjointBody => (_args) => { return QVoid.Instance; }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Borrow.cs b/src/Simulation/Simulators/QuantumExecutor/Borrow.cs new file mode 100644 index 00000000000..82d5062a4f1 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Borrow.cs @@ -0,0 +1,29 @@ +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimBorrow : Intrinsic.Borrow + { + private readonly QuantumExecutorSimulator sim; + public QuantumExecutorSimBorrow(QuantumExecutorSimulator m) : base(m){ + sim = m; + } + + public override Qubit Apply() + { + IQArray qubits = sim.QubitManager.Borrow(1); + sim.QuantumExecutor.OnBorrowQubits(qubits); + return qubits[0]; + } + + public override IQArray Apply( long count ) + { + IQArray qubits = sim.QubitManager.Borrow(1); + sim.QuantumExecutor.OnBorrowQubits(qubits); + return qubits; + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs new file mode 100644 index 00000000000..11eb7bf8ac8 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs @@ -0,0 +1,116 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class SimApplyIfElse : Extensions.ApplyIfElseIntrinsic + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyIfElse(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(Result, ICallable, ICallable), QVoid> Body => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + } + + public class SimApplyIfElseA : Extensions.ApplyIfElseIntrinsicA + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyIfElseA(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(Result, IAdjointable, IAdjointable), QVoid> Body => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(Result, IAdjointable, IAdjointable), QVoid> AdjointBody => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Adjoint.Apply(QVoid.Instance), + () => onOne.Adjoint.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + } + + public class SimApplyIfElseC : Extensions.ApplyIfElseIntrinsicC + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyIfElseC(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(Result, IControllable, IControllable), QVoid> Body => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> ControlledBody => + (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + Simulator.QuantumExecutor.ClassicallyControlled( + measurementResult, () => onZero.Controlled.Apply(ctrls), () => onOne.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; + } + + public class SimApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyIfElseCA(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(Result, IUnitary, IUnitary), QVoid> Body => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(Result, IUnitary, IUnitary), QVoid> AdjointBody => (q) => + { + var (measurementResult, onZero, onOne) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Adjoint.Apply(QVoid.Instance), + () => onOne.Adjoint.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Controlled.Apply(ctrls), + () => onOne.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => + (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Controlled.Adjoint.Apply(ctrls), + () => onOne.Controlled.Adjoint.Apply(ctrls)); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs new file mode 100644 index 00000000000..07bda4eb33c --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs @@ -0,0 +1,124 @@ +namespace Microsoft.Quantum.Simulation.QuantumExecutor.Extensions +{ + open Microsoft.Quantum.Intrinsic; + + operation NoOp() : Unit is Ctl + Adj {} + + operation Delay<'T> ( op : ('T => Unit), arg : 'T, aux : Unit ) : Unit { + op(arg); + } + + operation DelayC<'T> ( op : ('T => Unit is Ctl), arg : 'T, aux : Unit ) : Unit is Ctl { + op(arg); + } + + operation DelayA<'T> ( op : ('T => Unit is Adj), arg : 'T, aux : Unit ) : Unit is Adj { + op(arg); + } + + operation DelayCA<'T> ( op : ('T => Unit is Ctl + Adj), arg : 'T, aux : Unit ) : Unit is Ctl + Adj { + op(arg); + } + + + operation ApplyIfElseIntrinsic( measurementResult : Result, onResultZeroOp : (Unit => Unit) , onResultOneOp : (Unit => Unit) ) : Unit { + body intrinsic; + } + + operation ApplyIfElseIntrinsicA( measurementResult : Result, onResultZeroOp : (Unit => Unit is Adj) , onResultOneOp : (Unit => Unit is Adj) ) : Unit { + body intrinsic; + adjoint intrinsic; + } + + operation ApplyIfElseIntrinsicC( measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl) ) : Unit { + body intrinsic; + controlled intrinsic; + } + + operation ApplyIfElseIntrinsicCA( measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj) ) : Unit { + body intrinsic; + adjoint intrinsic; + controlled intrinsic; + controlled adjoint intrinsic; + } + + + operation ApplyIfElse<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) , (onResultOneOp : ('U => Unit), oneArg : 'U) ) : Unit { + let zeroOp = Delay(onResultZeroOp,zeroArg,_); + let oneOp = Delay(onResultOneOp,oneArg,_); + ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + } + +// operation ApplyIfElseArray<'T,'U>( measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit), equalArg : 'T) , (onNonEqualOp : ('U => Unit), nonEqualArg : 'U) ) : Unit { +// let equalOp = Delay(onEqualOp,equalArg,_); +// let nonEqualOp = Delay(onNonEqualOp,nonEqualArg,_); // normalize spaces !!! +// //ApplyIfElseIntrinsic( measurementResults, resultsValues, equalOp, nonEqualOp ); // wrong!!! +// } + + operation ApplyIfElseA<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj), oneArg : 'U) ) : Unit is Adj { + let zeroOp = DelayA(onResultZeroOp,zeroArg,_); + let oneOp = DelayA(onResultOneOp,oneArg,_); + ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfElseC<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Ctl), oneArg : 'U) ) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp,zeroArg,_); + let oneOp = DelayC(onResultOneOp,oneArg,_); + ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfElseCA<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj + Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj + Ctl), oneArg : 'U) ) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp,zeroArg,_); + let oneOp = DelayCA(onResultOneOp,oneArg,_); + ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfZero<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) ) : Unit { + let zeroOp = Delay(onResultZeroOp,zeroArg,_); + let oneOp = Delay(NoOp, (),_); + ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfZeroA<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) ) : Unit is Adj{ + let zeroOp = DelayA(onResultZeroOp,zeroArg,_); + let oneOp = DelayA(NoOp, (),_); + ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfZeroC<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) ) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp,zeroArg,_); + let oneOp = DelayC(NoOp, (),_); + ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfZeroCA<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl + Adj), zeroArg : 'T) ) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp,zeroArg,_); + let oneOp = DelayCA(NoOp, (),_); + ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfOne<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit), oneArg : 'T) ) : Unit { + let oneOp = Delay(onResultOneOp,oneArg,_); + let zeroOp = Delay(NoOp, (),_); + ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfOneA<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T) ) : Unit is Adj { + let oneOp = DelayA(onResultOneOp,oneArg,_); + let zeroOp = DelayA(NoOp, (),_); + ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfOneC<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T) ) : Unit is Ctl { + let oneOp = DelayC(onResultOneOp,oneArg,_); + let zeroOp = DelayC(NoOp, (),_); + ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + } + + operation ApplyIfOneCA<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl + Adj), oneArg : 'T) ) : Unit is Ctl + Adj { + let oneOp = DelayCA(onResultOneOp,oneArg,_); + let zeroOp = DelayCA(NoOp, (),_); + ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + } + +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Dump.cs b/src/Simulation/Simulators/QuantumExecutor/Dump.cs new file mode 100644 index 00000000000..ce7c997051a --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Dump.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Linq; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + /// + /// Dumps the wave function for the given qubits into the given target. + /// If the target is QVoid or an empty string, it dumps it to the console + /// using the `Message` function, otherwise it dumps the content into a file + /// with the given name. + /// DumpMachine dumps the entire wave function, + /// DumpRegister attempts to create the wave function or the resulting subsystem; if it fails + /// because the qubits are entangled with some external qubit, it just generates a message. + /// + protected virtual QVoid DumpMachine(T target) + { + QuantumExecutor.OnDumpMachine(target); + return QVoid.Instance; + } + + protected virtual QVoid DumpRegister(T target, IQArray qubits) + { + QuantumExecutor.OnDumpRegister(target, qubits); + return QVoid.Instance; + } + + public class QuantumExecutorSimDumpMachine : Quantum.Diagnostics.DumpMachine + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimDumpMachine(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (location) => + { + if (location == null) { throw new ArgumentNullException(nameof(location)); } + + return Simulator.DumpMachine(location); + }; + } + + public class QuantumExecutorSimDumpRegister : Quantum.Diagnostics.DumpRegister + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimDumpRegister(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(T, IQArray), QVoid> Body => (__in) => + { + var (location, qubits) = __in; + + if (location == null) { throw new ArgumentNullException(nameof(location)); } + return Simulator.DumpRegister(location, qubits); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs new file mode 100644 index 00000000000..fc8636c69f7 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + /// + /// An example of IQuantumExecutor that throws for every call. + /// + class EmptyQuantumExecutor : IQuantumExecutor + { + public virtual void Assert(IQArray bases, IQArray qubits, Result result, string msg) + { + } + + public virtual void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol) + { + } + + public virtual void ClassicallyControlled(Result measurementResult, Action onZero, Action onOne) + { + throw new NotImplementedException(); + } + + public virtual void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ControlledH(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR1(IQArray controls, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledS(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledSAdj(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2) + { + throw new NotImplementedException(); + } + + public virtual void ControlledT(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledTAdj(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledX(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledY(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledZ(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Exp(IQArray paulis, double theta, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void H(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual Result M(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual Result Measure(IQArray bases, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void OnAllocateQubits(IQArray qubits) + { + } + + public virtual void OnBorrowQubits(IQArray qubits) + { + } + + public virtual void OnDumpMachine(T location) + { + } + + public virtual void OnDumpRegister(T location, IQArray qubits) + { + } + + public virtual void OnMessage(string msg) + { + } + + public virtual void OnOperationEnd(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnOperationStart(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo) + { + } + + public virtual void OnReleaseQubits(IQArray qubits) + { + } + + public virtual void OnReturnQubits(IQArray qubits) + { + } + + public virtual void R(Pauli axis, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void R1(double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void R1Frac(long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Reset(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void RFrac(Pauli axis, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void S(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void SAdj(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void SWAP(Qubit qubit1, Qubit qubit2) + { + throw new NotImplementedException(); + } + + public virtual void T(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void TAdj(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void X(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Y(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Z(Qubit qubit) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Exp.cs b/src/Simulation/Simulators/QuantumExecutor/Exp.cs new file mode 100644 index 00000000000..e809f9dce13 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Exp.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimExp : Quantum.Intrinsic.Exp + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimExp(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, double, IQArray), QVoid> Body => (_args) => + { + + var (paulis, theta, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumExecutor.Exp(newPaulis, theta, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, double, IQArray), QVoid> AdjointBody => (_args) => + { + var (paulis, angle, qubits) = _args; + return this.Body.Invoke((paulis, -angle, qubits)); + }; + + public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledBody => (_args) => + { + + var (ctrls, (paulis, theta, qubits)) = _args; + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumExecutor.ControlledExp(ctrls, newPaulis, theta, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (paulis, angle, qubits)) = _args; + + return this.ControlledBody.Invoke((ctrls, (paulis, -angle, qubits))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs b/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs new file mode 100644 index 00000000000..7407a42ab99 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs @@ -0,0 +1,65 @@ +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; +using System; +using System.Collections.Generic; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimExpFrac : Quantum.Intrinsic.ExpFrac + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimExpFrac(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, long, long, IQArray), QVoid> Body => (_args) => + { + + var (paulis, nom, den, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException( + $"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + + Simulator.QuantumExecutor.ExpFrac(newPaulis, nom, den, newQubits); + return QVoid.Instance; + }; + + public override Func<(IQArray, long, long, IQArray), QVoid> AdjointBody => (_args) => + { + var (paulis, nom, den, qubits) = _args; + return this.Body.Invoke((paulis, -nom, den, qubits)); + }; + + public override Func<(IQArray, (IQArray, long, long, IQArray)), QVoid> + ControlledBody => (_args) => + { + + var (ctrls, (paulis, nom, den, qubits)) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException( + $"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumExecutor.ControlledExpFrac(ctrls, newPaulis, nom, den, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, long, long, IQArray)), QVoid> + ControlledAdjointBody => (_args) => + { + var (ctrls, (paulis, nom, den, qubits)) = _args; + + return this.ControlledBody.Invoke((ctrls, (paulis, -nom, den, qubits))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/H.cs b/src/Simulation/Simulators/QuantumExecutor/H.cs new file mode 100644 index 00000000000..bea3fee8920 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/H.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimH : Quantum.Intrinsic.H + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimH(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.H(q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (args) => + { + + var (ctrls, q1) = args; + Simulator.QuantumExecutor.ControlledH(ctrls,q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/M.cs b/src/Simulation/Simulators/QuantumExecutor/M.cs new file mode 100644 index 00000000000..573ddc3ebc9 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/M.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimM : Quantum.Intrinsic.M + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimM(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q) => + { + return Simulator.QuantumExecutor.M(q); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Measure.cs b/src/Simulation/Simulators/QuantumExecutor/Measure.cs new file mode 100644 index 00000000000..6c8c2dd90d7 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Measure.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimMeasure : Quantum.Intrinsic.Measure + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimMeasure(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray), Result> Body => (_args) => + { + var (paulis, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size"); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + return Simulator.QuantumExecutor.Measure( newPaulis, newQubits); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs b/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs new file mode 100644 index 00000000000..bf1ad0cfe91 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs @@ -0,0 +1,46 @@ +using System; + +using Microsoft.Quantum.Simulation.Common; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + /// + /// Simulator that redirects all the calls to a class implementing interface. + /// + public partial class QuantumExecutorSimulator : SimulatorBase + { + private const int PreallocatedQubitCount = 1000; + /// + /// Random number generator used for Microsoft.Quantum.Intrinsic.Random + /// + public readonly System.Random random; + + public override string Name => "QuantumExecutorSimulator"; + + /// + /// An instance of a class implementing interface that this simulator wraps. + /// + public IQuantumExecutor QuantumExecutor + { + get; + private set; + } + + /// + /// + /// + /// An instance of a class implementing interface to be wrapped. If the parameter is null is used. + /// An instance of a class implementing interface. If the parameter is null is used. + /// A seed to be used by Q# Microsoft.Quantum.Intrinsic.Random operation. + public QuantumExecutorSimulator(IQuantumExecutor quantumExecutor = null, IQubitManager qubitManager = null, int? randomSeed = null) + : base(qubitManager ?? new QubitManagerTrackingScope(PreallocatedQubitCount, mayExtendCapacity:true, disableBorrowing:false)) + { + random = new System.Random(randomSeed == null ? DateTime.Now.Millisecond : randomSeed.Value); + QuantumExecutor = quantumExecutor ?? new EmptyQuantumExecutor(); + OnOperationStart += QuantumExecutor.OnOperationStart; + OnOperationEnd += QuantumExecutor.OnOperationEnd; + OnLog += QuantumExecutor.OnMessage; + } + + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/R.cs b/src/Simulation/Simulators/QuantumExecutor/R.cs new file mode 100644 index 00000000000..e58e03f7eb1 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/R.cs @@ -0,0 +1,54 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimR : Quantum.Intrinsic.R + { + + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimR(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Pauli, double, Qubit), QVoid> Body => (_args) => + { + + var (basis, angle, q1) = _args; + if (basis != Pauli.PauliI) + { + Simulator.QuantumExecutor.R(basis, angle,q1); + } + return QVoid.Instance; + }; + + public override Func<(Pauli, double, Qubit), QVoid> AdjointBody => (_args) => + { + var (basis, angle, q1) = _args; + return this.Body.Invoke((basis, -angle, q1)); + }; + + public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledBody => (_args) => + { + + var (ctrls, (basis, angle, q1)) = _args; + Simulator.QuantumExecutor.ControlledR(ctrls, basis, angle, q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (basis, angle, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (basis, -angle, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/R1.cs b/src/Simulation/Simulators/QuantumExecutor/R1.cs new file mode 100644 index 00000000000..b94bd038b40 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/R1.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimR1 : Quantum.Intrinsic.R1 + { + + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimR1(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(double, Qubit), QVoid> Body => (_args) => + { + + var (angle, q1) = _args; + Simulator.QuantumExecutor.R1(angle, q1); + return QVoid.Instance; + }; + + public override Func<(double, Qubit), QVoid> AdjointBody => (_args) => + { + var (angle, q1) = _args; + return this.Body.Invoke((-angle, q1)); + }; + + public override Func<(IQArray, ( double, Qubit)), QVoid> ControlledBody => (_args) => + { + + var (ctrls, (angle, q1)) = _args; + Simulator.QuantumExecutor.ControlledR1(ctrls, angle, q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, (double, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (angle, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (-angle, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs b/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs new file mode 100644 index 00000000000..de2e6f4f22f --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs @@ -0,0 +1,53 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimR1Frac : Quantum.Intrinsic.R1Frac + { + + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimR1Frac(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(long, long, Qubit), QVoid> Body => (_args) => + { + + var (num, denom , q1) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumExecutor.R1Frac(numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(long, long, Qubit), QVoid> AdjointBody => (_args) => + { + var (num, denom, q1) = _args; + return this.Body.Invoke((-num, denom, q1)); + }; + + public override Func<(IQArray, (long, long, Qubit)), QVoid> ControlledBody => (_args) => + { + + var (ctrls, (num, denom, q1)) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumExecutor.ControlledR1Frac(ctrls, numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, (long, long, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (num, denom, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (-num, denom, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/RFrac.cs b/src/Simulation/Simulators/QuantumExecutor/RFrac.cs new file mode 100644 index 00000000000..27d9955154f --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/RFrac.cs @@ -0,0 +1,56 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimRFrac : Quantum.Intrinsic.RFrac + { + + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimRFrac(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Pauli, long, long, Qubit), QVoid> Body => (_args) => + { + + var (basis, num, denom , q1) = _args; + if (basis != Pauli.PauliI) + { + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumExecutor.RFrac(basis, numNew, denomNew, q1); + } + return QVoid.Instance; + }; + + public override Func<(Pauli, long, long, Qubit), QVoid> AdjointBody => (_args) => + { + var (basis, num, denom, q1) = _args; + return this.Body.Invoke((basis, -num, denom, q1)); + }; + + public override Func<(IQArray, (Pauli, long, long, Qubit)), QVoid> ControlledBody => (_args) => + { + + var (ctrls, (basis, num, denom, q1)) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumExecutor.ControlledRFrac(ctrls, basis, numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Pauli, long, long, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (basis, num, denom, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (basis, -num, denom, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Release.cs b/src/Simulation/Simulators/QuantumExecutor/Release.cs new file mode 100644 index 00000000000..4447c365f86 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Release.cs @@ -0,0 +1,27 @@ +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimRelease : Intrinsic.Release + { + private readonly QuantumExecutorSimulator sim; + public QuantumExecutorSimRelease(QuantumExecutorSimulator m) : base(m){ + sim = m; + } + + public override void Apply(Qubit q) + { + sim.QuantumExecutor.OnReleaseQubits(new QArray(q)); + sim.QubitManager.Release(q); + } + + public override void Apply(IQArray qubits) + { + sim.QuantumExecutor.OnReleaseQubits(qubits); + sim.QubitManager.Release(qubits); + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumExecutor/Reset.cs b/src/Simulation/Simulators/QuantumExecutor/Reset.cs new file mode 100644 index 00000000000..6c655d06e1b --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Reset.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimReset : Quantum.Intrinsic.Reset + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimReset(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.Reset(q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Return.cs b/src/Simulation/Simulators/QuantumExecutor/Return.cs new file mode 100644 index 00000000000..cdeeb859aa6 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Return.cs @@ -0,0 +1,27 @@ +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + using Microsoft.Quantum.Simulation.Core; + + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimReturn : Intrinsic.Return + { + private readonly QuantumExecutorSimulator sim; + public QuantumExecutorSimReturn(QuantumExecutorSimulator m) : base(m){ + sim = m; + } + + public override void Apply(Qubit q) + { + sim.QuantumExecutor.OnReturnQubits(new QArray(q)); + sim.QubitManager.Return(q); + } + + public override void Apply(IQArray qubits) + { + sim.QuantumExecutor.OnReturnQubits(qubits); + sim.QubitManager.Return(qubits); + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumExecutor/S.cs b/src/Simulation/Simulators/QuantumExecutor/S.cs new file mode 100644 index 00000000000..510867fd758 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/S.cs @@ -0,0 +1,49 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimS : Quantum.Intrinsic.S + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimS(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.S(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumExecutor.ControlledS(ctrls, q1); + return QVoid.Instance; + }; + + public override Func AdjointBody => (q1) => + { + + Simulator.QuantumExecutor.SAdj(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumExecutor.ControlledSAdj(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/SWAP.cs b/src/Simulation/Simulators/QuantumExecutor/SWAP.cs new file mode 100644 index 00000000000..8aeb05eefdc --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/SWAP.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimSWAP : Quantum.Intrinsic.SWAP + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimSWAP(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Qubit,Qubit), QVoid> Body => (q1) => + { + + Simulator.QuantumExecutor.SWAP(q1.Item1, q1.Item2); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Qubit, Qubit)), QVoid> ControlledBody => (args) => + { + + var (ctrls, q1) = args; + Simulator.QuantumExecutor.ControlledSWAP(ctrls, q1.Item1, q1.Item2); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/T.cs b/src/Simulation/Simulators/QuantumExecutor/T.cs new file mode 100644 index 00000000000..06e650b6056 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/T.cs @@ -0,0 +1,52 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimT : Quantum.Intrinsic.T + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimT(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.T(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + + Simulator.QuantumExecutor.ControlledT(ctrls, q1); + + return QVoid.Instance; + }; + + public override Func AdjointBody => (q1) => + { + + Simulator.QuantumExecutor.TAdj(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumExecutor.ControlledTAdj(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/X.cs b/src/Simulation/Simulators/QuantumExecutor/X.cs new file mode 100644 index 00000000000..4bcb59e4f5b --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/X.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimX : Quantum.Intrinsic.X + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimX(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.X(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (args) => + { + + var (ctrls, q1) = args; + Simulator.QuantumExecutor.ControlledX(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Y.cs b/src/Simulation/Simulators/QuantumExecutor/Y.cs new file mode 100644 index 00000000000..89e37c6f1a1 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Y.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimY : Quantum.Intrinsic.Y + { + private QuantumExecutorSimulator Simulator { get; } + + + public QuantumExecutorSimY(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.Y(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumExecutor.ControlledY(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/Z.cs b/src/Simulation/Simulators/QuantumExecutor/Z.cs new file mode 100644 index 00000000000..8a37d2999b3 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/Z.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Quantum.Intrinsic; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public class QuantumExecutorSimZ : Quantum.Intrinsic.Z + { + private QuantumExecutorSimulator Simulator { get; } + + public QuantumExecutorSimZ(QuantumExecutorSimulator m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + + Simulator.QuantumExecutor.Z(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumExecutor.ControlledZ(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumExecutor/random.cs b/src/Simulation/Simulators/QuantumExecutor/random.cs new file mode 100644 index 00000000000..4f10b3a1e68 --- /dev/null +++ b/src/Simulation/Simulators/QuantumExecutor/random.cs @@ -0,0 +1,52 @@ +using Microsoft.Quantum.Simulation.Core; +using System; + +namespace Microsoft.Quantum.Simulation.QuantumExecutor +{ + public partial class QuantumExecutorSimulator + { + public static long SampleDistribution(IQArray unnormalizedDistribution, double uniformZeroOneSample) + { + double total = 0.0; + foreach (double prob in unnormalizedDistribution) + { + if (prob < 0) + { + throw new ExecutionFailException("Random expects array of non-negative doubles."); + } + total += prob; + } + + if (total == 0) + { + throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum."); + } + + double sample = uniformZeroOneSample * total; + double sum = unnormalizedDistribution[0]; + for (int i = 0; i < unnormalizedDistribution.Length - 1; ++i) + { + if (sum >= sample) + { + return i; + } + sum += unnormalizedDistribution[i]; + } + return unnormalizedDistribution.Length; + } + + public class QuantumExecutorSimRandom : Quantum.Intrinsic.Random + { + private QuantumExecutorSimulator Simulator { get; } + public QuantumExecutorSimRandom(QuantumExecutorSimulator m) : base(m) + { + Simulator = m; + } + + public override Func, Int64> Body => (p) => + { + return SampleDistribution(p, Simulator.random.NextDouble()); + }; + } + } +} From 4cb1647ae6a80ef45e10678b8bd261d997243694 Mon Sep 17 00:00:00 2001 From: Vadym Date: Tue, 29 Oct 2019 16:20:47 -0700 Subject: [PATCH 07/17] added PDB source extraction supoort --- ...Microsoft.Quantum.Simulation.Common.csproj | 4 + src/Simulation/Common/StackTrace.cs | 165 +++++------------- src/Simulation/Core/TypeExtensions.cs | 10 ++ .../CsharpGeneration/SimulationCode.fs | 6 +- .../Simulators.Tests/Circuits/Fail.qs | 23 ++- .../Simulators.Tests/StackTraceTests.cs | 88 ++++++++-- ...osoft.Quantum.Simulation.Simulators.csproj | 1 + 7 files changed, 154 insertions(+), 143 deletions(-) diff --git a/src/Simulation/Common/Microsoft.Quantum.Simulation.Common.csproj b/src/Simulation/Common/Microsoft.Quantum.Simulation.Common.csproj index 369209ad295..54886046904 100644 --- a/src/Simulation/Common/Microsoft.Quantum.Simulation.Common.csproj +++ b/src/Simulation/Common/Microsoft.Quantum.Simulation.Common.csproj @@ -8,6 +8,10 @@ x64 + + + + diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index 5eead854b85..e1ecf2fa605 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -39,6 +39,8 @@ public class StackFrame /// public int declarationEndLineNumber; + private readonly Lazy pdbFileLocation; + public StackFrame(ICallable _operation, IApplyData _argument) { operation = _operation; @@ -47,34 +49,23 @@ public StackFrame(ICallable _operation, IApplyData _argument) failedLineNumber = -1; declarationStartLineNumber = -1; declarationEndLineNumber = -1; + pdbFileLocation = new Lazy(() => PortablePdbSymbolReader.GetPDBLocation(operation)); } public string GetOperationSourceFromPDB() { - string result = null; - try - { - //TODO: - } - catch (Exception) - { - - } - return result; + return PortablePDBEmbeddedFilesCache.GetEmbeddedFileRange( + pdbFileLocation.Value, + sourceFile, + declarationStartLineNumber, + declarationEndLineNumber, + showLineNumbers: true, markedLine: failedLineNumber); } public string GetURLFromPDB() { - string result = null; - try - { - //TODO: - } - catch (Exception) - { - - } - return result; + string result = PortablePDBPathRemappingCache.TryGetFileUrl(pdbFileLocation.Value, sourceFile); + return PortablePdbSymbolReader.TryFormatGitHubUrl(result, failedLineNumber); } public override string ToString() @@ -137,96 +128,13 @@ void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo } } - public static ICallable UnwrapCallable(ICallable op) - { - ICallable res = op; - while (res as IWrappedOperation != null) - { - res = (res as IWrappedOperation).BaseOperation; - } - return res; - } - - class HalfOpenInterval : IEquatable - { - public readonly int start; - public readonly int end; - - public HalfOpenInterval(int start, int end) - { - if( start > end ) throw new ArgumentException($"Interval start:{start} must be less or equal to end:{end}."); - this.start = start; - this.end = end; - } - - public override bool Equals(object obj) - { - return Equals(obj as HalfOpenInterval); - } - - public bool Equals(HalfOpenInterval other) - { - return other != null && - start == other.start && - end == other.end; - } - - public override int GetHashCode() - { - return HashCode.Combine(start, end); - } - } - - class NonOverlappingHalfOpenIntervalSet - { - class NonOverlappinIntervalsComparator : IComparer - { - public int Compare(HalfOpenInterval x, HalfOpenInterval y) - { - if (x.end <= y.start) return -1; - if (x.start >= y.end) return 1; - if (x.start == y.start && x.end == y.end) return 0; - throw new ArgumentException("Compared intervals must be non-overlapping"); - } - } - public NonOverlappingHalfOpenIntervalSet(IEnumerable inervals) - { - throw new NotImplementedException(); - } - public bool Contains(int value) - { - throw new NotImplementedException(); - } - } - - static void PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) + static StackFrame[] PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) { - // TODO: change logic to check if given location in the known Q# call-stack locations - //List> qsharpSourceLocations = new List>(); - //foreach (System.Diagnostics.StackFrame csStackFrame in csharpCallStack) - //{ - // string fileName = csStackFrame.GetFileName(); - // if (System.IO.Path.GetExtension(fileName) == ".qs") - // { - // qsharpSourceLocations.Add(new Tuple(fileName, csStackFrame.GetFileLineNumber())); - // } - //} - - //string fileName = System.IO.Path.GetFullPath(qsharpSourceLocations[i].Item1); - //int failedLineNumber = qsharpSourceLocations[i].Item2; - //if (fileName == stackFrames[i].sourceFile && - // sourceLocation.StartLine <= failedLineNumber && - // ((failedLineNumber <= sourceLocation.EndLine) || sourceLocation.EndLine == -1)) - //{ - // stackFrames[i].failedLineNumber = failedLineNumber; - //} - - Dictionary> sourceLocations = new Dictionary>(); - foreach (StackFrame currentFrame in qsharpCallStack ) + foreach (StackFrame currentFrame in qsharpCallStack) { - ICallable op = UnwrapCallable(currentFrame.operation); + ICallable op = currentFrame.operation.UnwrapCallable(); object[] locations = op.GetType().GetCustomAttributes(typeof(SourceLocationAttribute), true); foreach (object location in locations) { @@ -234,32 +142,43 @@ static void PopulateSourceLocations(Stack qsharpCallStack, System.Di if (sourceLocation != null && sourceLocation.SpecializationKind == op.Variant) { currentFrame.sourceFile = System.IO.Path.GetFullPath(sourceLocation.SourceFile); - currentFrame.declarationStartLineNumber = sourceLocation.StartLine + 1; // note that attribute has base 0 line numbers - currentFrame.declarationEndLineNumber = sourceLocation.EndLine == -1 ? -1 : sourceLocation.EndLine + 1; + currentFrame.declarationStartLineNumber = sourceLocation.StartLine; // note that attribute has base 0 line numbers + currentFrame.declarationEndLineNumber = sourceLocation.EndLine; + } + } + } - List intervals = sourceLocations.GetValueOrDefault(currentFrame.sourceFile); - HalfOpenInterval currentRange = new HalfOpenInterval( - currentFrame.declarationStartLineNumber, - currentFrame.declarationEndLineNumber == -1 ? int.MaxValue : currentFrame.declarationEndLineNumber); - if (intervals == null) - { - sourceLocations.Add(currentFrame.sourceFile, new List(Enumerable.Repeat(currentRange,1)); - } - else - { - intervals.Add(currentRange); - } + StackFrame[] qsharpStackFrames = qsharpCallStack.ToArray(); + int qsharpStackFrameId = 0; + for (int csharpStackFrameId = 0; csharpStackFrameId < csharpCallStack.Length; ++csharpStackFrameId) + { + string fileName = csharpCallStack[csharpStackFrameId].GetFileName(); + if ( fileName != null ) + { + fileName = System.IO.Path.GetFullPath(fileName); + int failedLineNumber = csharpCallStack[csharpStackFrameId].GetFileLineNumber(); + StackFrame currentQsharpStackFrame = qsharpStackFrames[qsharpStackFrameId]; + if (fileName == currentQsharpStackFrame.sourceFile && + currentQsharpStackFrame.declarationStartLineNumber <= failedLineNumber && + ( + (failedLineNumber < currentQsharpStackFrame.declarationEndLineNumber) || + (currentQsharpStackFrame.declarationEndLineNumber == -1) + ) + ) + { + currentQsharpStackFrame.failedLineNumber = failedLineNumber; + qsharpStackFrameId++; } } } + return qsharpStackFrames; } - public Stack CallStack + public StackFrame[] CallStack { get { - PopulateSourceLocations(callStack, frames); - return callStack; + return PopulateSourceLocations(callStack, frames); } } } diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index 9822b37f373..5bfb38c72eb 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -368,5 +368,15 @@ public static string QSharpType(this Type t) return t.Name; } + + public static ICallable UnwrapCallable(this ICallable op) + { + ICallable res = op; + while (res as IWrappedOperation != null) + { + res = (res as IWrappedOperation).BaseOperation; + } + return res; + } } } diff --git a/src/Simulation/CsharpGeneration/SimulationCode.fs b/src/Simulation/CsharpGeneration/SimulationCode.fs index 5fe363851b7..21a5bb9f0de 100644 --- a/src/Simulation/CsharpGeneration/SimulationCode.fs +++ b/src/Simulation/CsharpGeneration/SimulationCode.fs @@ -347,7 +347,7 @@ module SimulationCode = ``#line`` ln n s | Some n, None -> startLine |> function | Some ln -> - ``#line`` ln n s + ``#line`` (ln + 1) n s | None -> s | _ -> s @@ -1020,12 +1020,12 @@ module SimulationCode = | QsControlledAdjoint -> "ControlledAdjoint" let body = (buildSpecializationBody context sp) let attribute = - let startLine = fst sp.Location.Offset + let startLine = fst sp.Location.Offset + 1 let endLine = match context.declarationPositions.TryGetValue sp.SourceFile with | true, startPositions -> let index = startPositions.IndexOf sp.Location.Offset - if index + 1 >= startPositions.Count then -1 else fst startPositions.[index + 1] + if index + 1 >= startPositions.Count then -1 else fst startPositions.[index + 1] + 1 //TODO: diagnostics. | false, _ -> startLine ``attribute`` None (ident "SourceLocation") [ diff --git a/src/Simulation/Simulators.Tests/Circuits/Fail.qs b/src/Simulation/Simulators.Tests/Circuits/Fail.qs index 834ef2f4af9..4d20fdea39c 100644 --- a/src/Simulation/Simulators.Tests/Circuits/Fail.qs +++ b/src/Simulation/Simulators.Tests/Circuits/Fail.qs @@ -3,8 +3,8 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { - function AlwaysFail() : Unit { - fail "Always fail"; + operation AlwaysFail() : Unit is Adj + Ctl{ + Fail(); } operation AlwaysFail1() : Unit is Adj + Ctl{ @@ -55,4 +55,23 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { operation GenericCtlFail1() : Unit is Adj + Ctl { Controlled GenericFail( new Qubit[0], (5,6)); } + + function Fail() : Unit { + fail "Always fail"; + } + + operation RecursionFail( a : Int) : Unit is Adj { + if ( a >= 1 ) + { + RecursionFail(a-1); + } + else + { + Fail(); + } + } + + operation RecursionFail1() : Unit { + RecursionFail(2); + } } \ No newline at end of file diff --git a/src/Simulation/Simulators.Tests/StackTraceTests.cs b/src/Simulation/Simulators.Tests/StackTraceTests.cs index 851bae4e0e7..3477f66244b 100644 --- a/src/Simulation/Simulators.Tests/StackTraceTests.cs +++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs @@ -11,6 +11,7 @@ using Microsoft.Quantum.Simulation.Simulators.Tests.Circuits; using Microsoft.Quantum.Simulation.Simulators.Exceptions; using Xunit.Abstractions; +using System.Text; namespace Microsoft.Quantum.Simulation.Simulators.Tests { @@ -36,7 +37,7 @@ public void AlwaysFail4Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(5, stackFrames.Length); @@ -59,6 +60,27 @@ public void AlwaysFail4Test() Assert.Equal(stackFrames[0].declarationStartLineNumber, stackFrames[0].failedLineNumber); Assert.Equal(stackFrames[1].declarationStartLineNumber, stackFrames[1].failedLineNumber); Assert.Equal(stackFrames[3].declarationStartLineNumber, stackFrames[3].failedLineNumber); + + for (int i = 0; i < stackFrames.Length; ++i) + { + Assert.StartsWith(@"https://github.com/", stackFrames[i].GetURLFromPDB()); + Assert.EndsWith($"#L{stackFrames[i].failedLineNumber}", stackFrames[i].GetURLFromPDB()); + } + + StringBuilder builder = new StringBuilder(); + builder.Append("13 ".PadLeft(PortablePDBEmbeddedFilesCache.lineNumberPaddingWidth)); + builder.AppendLine(" operation AlwaysFail2() : Unit is Adj + Ctl {"); + builder.Append("14 ".PadLeft(PortablePDBEmbeddedFilesCache.lineNumberPaddingWidth) + PortablePDBEmbeddedFilesCache.lineMarkPrefix); + builder.AppendLine(" Controlled AlwaysFail1(new Qubit[0],());"); + builder.Append("15 ".PadLeft(PortablePDBEmbeddedFilesCache.lineNumberPaddingWidth)); + builder.AppendLine(" }"); + Assert.Equal(builder.ToString(), stackFrames[2].GetOperationSourceFromPDB()); + + for( int i = 0; i < stackFrames.Length; ++i ) + { + output.WriteLine($"operation:{stackFrames[i].operation.FullName}"); + output.WriteLine(stackFrames[i].GetOperationSourceFromPDB()); + } } } @@ -76,7 +98,7 @@ public void GenericFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -103,7 +125,7 @@ public void GenericFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -115,8 +137,8 @@ public void GenericFail1Test() Assert.Equal(OperationFunctor.Adjoint, stackFrames[1].operation.Variant); Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); - Assert.Equal(5, stackFrames[0].failedLineNumber); - Assert.Equal(23, stackFrames[1].failedLineNumber); + Assert.Equal(6, stackFrames[0].failedLineNumber); + Assert.Equal(24, stackFrames[1].failedLineNumber); Assert.Equal(52, stackFrames[2].failedLineNumber); } } @@ -130,7 +152,7 @@ public void GenericFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -142,8 +164,8 @@ public void GenericFail1Test() Assert.Equal(OperationFunctor.Controlled, stackFrames[1].operation.Variant); Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); - Assert.Equal(5, stackFrames[0].failedLineNumber); - Assert.Equal(23, stackFrames[1].failedLineNumber); + Assert.Equal(6, stackFrames[0].failedLineNumber); + Assert.Equal(24, stackFrames[1].failedLineNumber); Assert.Equal(56, stackFrames[2].failedLineNumber); } } @@ -163,7 +185,7 @@ public void PartialFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -190,7 +212,7 @@ public void PartialFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -202,8 +224,8 @@ public void PartialFail1Test() Assert.Equal(OperationFunctor.Adjoint, stackFrames[1].operation.Variant); Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); - Assert.Equal(5, stackFrames[0].failedLineNumber); - Assert.Equal(31, stackFrames[1].failedLineNumber); + Assert.Equal(6, stackFrames[0].failedLineNumber); + Assert.Equal(32, stackFrames[1].failedLineNumber); Assert.Equal(43, stackFrames[2].failedLineNumber); } } @@ -217,7 +239,7 @@ public void PartialFail1Test() } catch (ExecutionFailException) { - StackFrame[] stackFrames = sc.CallStack.ToArray(); + StackFrame[] stackFrames = sc.CallStack; Assert.Equal(3, stackFrames.Length); @@ -229,11 +251,47 @@ public void PartialFail1Test() Assert.Equal(OperationFunctor.Controlled, stackFrames[1].operation.Variant); Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); - Assert.Equal(5, stackFrames[0].failedLineNumber); - Assert.Equal(31, stackFrames[1].failedLineNumber); + Assert.Equal(6, stackFrames[0].failedLineNumber); + Assert.Equal(32, stackFrames[1].failedLineNumber); Assert.Equal(48, stackFrames[2].failedLineNumber); } } } + + [Fact] + public void RecursionFail1Test() + { + ToffoliSimulator sim = new ToffoliSimulator(); + + { + StackTraceCollector sc = new StackTraceCollector(sim); + ICallable op = sim.Get(); + try + { + QVoid res = op.Apply(QVoid.Instance); + } + catch (ExecutionFailException) + { + StackFrame[] stackFrames = sc.CallStack; + + Assert.Equal(4, stackFrames.Length); + + Assert.Equal(namespacePrefix + "RecursionFail", stackFrames[0].operation.FullName); + Assert.Equal(namespacePrefix + "RecursionFail", stackFrames[1].operation.FullName); + Assert.Equal(namespacePrefix + "RecursionFail", stackFrames[2].operation.FullName); + Assert.Equal(namespacePrefix + "RecursionFail1", stackFrames[3].operation.FullName); + + Assert.Equal(OperationFunctor.Body, stackFrames[0].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[1].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[2].operation.Variant); + Assert.Equal(OperationFunctor.Body, stackFrames[3].operation.Variant); + + Assert.Equal(70, stackFrames[0].failedLineNumber); + Assert.Equal(66, stackFrames[1].failedLineNumber); + Assert.Equal(66, stackFrames[2].failedLineNumber); + Assert.Equal(75, stackFrames[3].failedLineNumber); + } + } + } } } \ No newline at end of file diff --git a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulation.Simulators.csproj b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulation.Simulators.csproj index 64d3e4bb24e..565987988c9 100644 --- a/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulation.Simulators.csproj +++ b/src/Simulation/Simulators.Tests/Tests.Microsoft.Quantum.Simulation.Simulators.csproj @@ -1,6 +1,7 @@  + netcoreapp3.0 From 40f7916b636becc7d611b9bae38ecd9920fc132e Mon Sep 17 00:00:00 2001 From: Vadym Date: Tue, 29 Oct 2019 18:33:52 -0700 Subject: [PATCH 08/17] extending tests; fixing url issues --- src/Simulation/Common/SimulatorBase.cs | 41 +++++++-- src/Simulation/Common/StackTrace.cs | 83 +++++++++++++++---- .../Simulators.Tests/StackTraceTests.cs | 17 ++++ 3 files changed, 120 insertions(+), 21 deletions(-) diff --git a/src/Simulation/Common/SimulatorBase.cs b/src/Simulation/Common/SimulatorBase.cs index 3bc17a26e4e..b0dc7dcba3d 100644 --- a/src/Simulation/Common/SimulatorBase.cs +++ b/src/Simulation/Common/SimulatorBase.cs @@ -98,14 +98,34 @@ public override AbstractCallable CreateInstance(Type t) return result; } + public virtual O RunSync(I args) where T : AbstractCallable, ICallable + { + O res = default(O); + var op = Get(); + try + { + res = op.Apply(args); + } + catch (Exception e) // Dumps q# call-stack in case of exception if CallStack tracking was enabled + { + StackFrame[] qsharpStackFrames = this.CallStack; + if (qsharpStackFrames != null) + { + OnLog?.Invoke($"Unhandled Exception: {e.GetType().FullName}: {e.Message}"); + foreach (StackFrame sf in qsharpStackFrames) + { + OnLog?.Invoke(sf.ToStringWithBestSourceLocation()); + } + } + OnLog?.Invoke(""); + throw; + } + return res; + } public virtual Task Run(I args) where T : AbstractCallable, ICallable { - return Task.Run(() => - { - var op = Get(); - return op.Apply(args); - }); + return Task.Run(() => RunSync(args)); } /// @@ -346,5 +366,16 @@ public virtual void Fail(System.Runtime.ExceptionServices.ExceptionDispatchInfo { OnFail?.Invoke(exceptionInfo); } + + #region Stack trace collection support + private StackTraceCollector stackTraceCollector = null; + + public void EnableStackTrace() + { + stackTraceCollector = new StackTraceCollector(this); + } + + public StackFrame[] CallStack => stackTraceCollector?.CallStack; + #endregion } } diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index e1ecf2fa605..0dacf7d98cd 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -26,7 +26,7 @@ public class StackFrame /// One based line number in the operation that resulted in failure. Note that for automatically derived Adjoint and Controlled /// variants of the operation, the line always points to the operation declaration /// - public int failedLineNumber; + public int failedLineNumber = -2; /// /// One based line number where the declaration starts. @@ -39,46 +39,81 @@ public class StackFrame /// public int declarationEndLineNumber; - private readonly Lazy pdbFileLocation; - public StackFrame(ICallable _operation, IApplyData _argument) { operation = _operation; argument = _argument; - sourceFile = null; - failedLineNumber = -1; - declarationStartLineNumber = -1; - declarationEndLineNumber = -1; - pdbFileLocation = new Lazy(() => PortablePdbSymbolReader.GetPDBLocation(operation)); } + /// + /// Uses PortablePDBs and SourceLink to get the source of failed operation. + /// public string GetOperationSourceFromPDB() { + string pdbFileLocation = PortablePdbSymbolReader.GetPDBLocation(operation); return PortablePDBEmbeddedFilesCache.GetEmbeddedFileRange( - pdbFileLocation.Value, + pdbFileLocation, sourceFile, declarationStartLineNumber, declarationEndLineNumber, showLineNumbers: true, markedLine: failedLineNumber); } + /// + /// Uses PortablePDBs and SourceLink to get URL for file and line number. + /// + /// public string GetURLFromPDB() { - string result = PortablePDBPathRemappingCache.TryGetFileUrl(pdbFileLocation.Value, sourceFile); + string pdbFileLocation = PortablePdbSymbolReader.GetPDBLocation(operation); + Tuple result = PortablePDBPathRemappingCache.TryGetFileUrl(pdbFileLocation, sourceFile); return PortablePdbSymbolReader.TryFormatGitHubUrl(result, failedLineNumber); } public override string ToString() { - string location = GetURLFromPDB() ?? $"{sourceFile}:line {failedLineNumber}"; - return $"in {operation.FullName} on {location}"; + return $"in {operation.FullName} on {sourceFile}:line {failedLineNumber}"; + } + + /// + /// The same as , but tries to point to best source location. + /// If the source is not available on local machine, source location will be replaced + /// by URL pointing to GitHub repository. + /// This is more costly than because it checks if source file exists on disk. + /// If the file does not exist it calls to get the URL + /// which is also more costly than . + /// + public virtual string ToStringWithBestSourceLocation() + { + string message = ToString(); + if (System.IO.File.Exists(sourceFile)) + { + return message; + } + else + { + string url = GetURLFromPDB(); + if (url == null) + { + return message; + } + else + { + return $"in {operation.FullName} on {url}"; + } + } } } + /// + /// Tracks Q# call-stack till the first failure resulting in + /// event invocation. + /// public class StackTraceCollector { private readonly Stack callStack; private System.Diagnostics.StackFrame[] frames = null; + StackFrame[] stackFramesWithLocations = null; bool hasFailed = false; public StackTraceCollector(SimulatorBase sim) @@ -91,7 +126,10 @@ public StackTraceCollector(SimulatorBase sim) void OnOperationStart(ICallable callable, IApplyData arg) { - callStack.Push(new StackFrame(callable, arg)); + if (!hasFailed) + { + callStack.Push(new StackFrame(callable, arg)); + } } void OnOperationEnd(ICallable callable, IApplyData arg) @@ -128,8 +166,6 @@ void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo } } - - static StackFrame[] PopulateSourceLocations(Stack qsharpCallStack, System.Diagnostics.StackFrame[] csharpCallStack) { foreach (StackFrame currentFrame in qsharpCallStack) @@ -174,11 +210,26 @@ static StackFrame[] PopulateSourceLocations(Stack qsharpCallStack, S return qsharpStackFrames; } + /// + /// If failure has happened returns the call-stack at time of failure. + /// Returns null if the failure has not happened. + /// public StackFrame[] CallStack { get { - return PopulateSourceLocations(callStack, frames); + if (hasFailed) + { + if( stackFramesWithLocations == null ) + { + stackFramesWithLocations = PopulateSourceLocations(callStack, frames); + } + return stackFramesWithLocations; + } + else + { + return null; + } } } } diff --git a/src/Simulation/Simulators.Tests/StackTraceTests.cs b/src/Simulation/Simulators.Tests/StackTraceTests.cs index 3477f66244b..602b9fff854 100644 --- a/src/Simulation/Simulators.Tests/StackTraceTests.cs +++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs @@ -293,5 +293,22 @@ public void RecursionFail1Test() } } } + + [Fact] + public void ErrorLogTest() + { + ToffoliSimulator sim = new ToffoliSimulator(); + sim.EnableStackTrace(); + StringBuilder stringBuilder = new StringBuilder(); + sim.OnLog += (msg) => stringBuilder.AppendLine(msg); + try + { + QVoid res = sim.RunSync(QVoid.Instance); + } + catch (ExecutionFailException) + { + } + output.WriteLine(stringBuilder.ToString()); + } } } \ No newline at end of file From f098a43f1954d63aeeb67f973a276ac8beaf8bbb Mon Sep 17 00:00:00 2001 From: Vadym Date: Tue, 29 Oct 2019 18:53:48 -0700 Subject: [PATCH 09/17] adding portablePdbreader --- src/Simulation/Common/PortablePDBReader.cs | 260 +++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 src/Simulation/Common/PortablePDBReader.cs diff --git a/src/Simulation/Common/PortablePDBReader.cs b/src/Simulation/Common/PortablePDBReader.cs new file mode 100644 index 00000000000..b7fbf3d2bbb --- /dev/null +++ b/src/Simulation/Common/PortablePDBReader.cs @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Quantum.Simulation.Common +{ + using System.Collections.Generic; + using System.Reflection.Metadata; + using System; + using System.IO; + using System.IO.Compression; + using System.Text; + using Newtonsoft.Json.Linq; + using System.Text.RegularExpressions; + using Microsoft.Quantum.Simulation.Core; + + // Based on https://github.com/microsoft/BPerf/blob/master/WebViewer/Microsoft.BPerf.SymbolicInformation.ProgramDatabase/PortablePdbSymbolReader.cs + class PortablePdbSymbolReader + { + private static readonly Guid SourceLink = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A"); + + private static readonly Guid EmbeddedSource = new Guid("0E8A571B-6926-466E-B4AD-8AB04611F5FE"); + + public static Dictionary GetEmbeddedFiles(string pdbFilePath) + { + Dictionary embeddedFiles = new Dictionary(); + + using (FileStream stream = File.OpenRead(pdbFilePath)) + using (MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream)) + { + MetadataReader metadataReader = metadataReaderProvider.GetMetadataReader(); + CustomDebugInformationHandleCollection customDebugInformationHandles = metadataReader.CustomDebugInformation; + foreach (var customDebugInformationHandle in customDebugInformationHandles) + { + CustomDebugInformation customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle); + if (metadataReader.GetGuid(customDebugInformation.Kind) == EmbeddedSource) + { + byte[] embeddedSource = metadataReader.GetBlobBytes(customDebugInformation.Value); + Int32 uncompressedSourceFileSize = BitConverter.ToInt32(embeddedSource, 0); + if (uncompressedSourceFileSize != 0) + { + Document document = metadataReader.GetDocument((DocumentHandle)customDebugInformation.Parent); + string sourceFileName = System.IO.Path.GetFullPath(metadataReader.GetString(document.Name)); + + // See https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PortablePdb-Metadata.md#embedded-source-c-and-vb-compilers + // Decompress embedded source + MemoryStream memoryStream = + new MemoryStream(embeddedSource, sizeof(Int32), embeddedSource.Length - sizeof(Int32)); + + using (DeflateStream decompressionStream = new DeflateStream(memoryStream, CompressionMode.Decompress)) + { + MemoryStream decompressed = new MemoryStream(new byte[uncompressedSourceFileSize], true); + decompressionStream.CopyTo(decompressed); + embeddedFiles.Add(sourceFileName, Encoding.UTF8.GetString(decompressed.ToArray())); + } + } + } + } + } + return embeddedFiles; + } + + public static string GetSourceLinkString(string pdbFilePath) + { + using (FileStream stream = File.OpenRead(pdbFilePath)) + { + using (MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream)) + { + MetadataReader metadataReader = metadataReaderProvider.GetMetadataReader(); + CustomDebugInformationHandleCollection customDebugInformationHandles = metadataReader.CustomDebugInformation; + foreach (var customDebugInformationHandle in customDebugInformationHandles) + { + CustomDebugInformation customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle); + + if (metadataReader.GetGuid(customDebugInformation.Kind) == SourceLink) + { + return Encoding.UTF8.GetString(metadataReader.GetBlobBytes(customDebugInformation.Value)); + } + } + } + } + return null; + } + + public static Tuple[] ParseSourceLinkString(string SourceLinkString) + { + if (SourceLinkString == null) return null; + List> pairs = new List>(); + JObject jsonResponse = JObject.Parse(SourceLinkString); + JObject document = JObject.Parse(jsonResponse["documents"].ToString()); + foreach (JProperty property in document.Properties()) + { + string fullPath = System.IO.Path.GetFullPath(property.Name.Replace("*", "")); + pairs.Add(new Tuple(fullPath, property.Value.ToObject().Replace("*", ""))); + } + return pairs.ToArray(); + } + + public static string TryFormatGitHubUrl(Tuple rawUrl, int lineNumber) + { + if (rawUrl == null) + return null; + + string result = null; + if (rawUrl.Item1.StartsWith(@"https://raw.githubusercontent.com")) + { + result = Regex.Replace(rawUrl.Item1, "[a-f0-9]+" + Regex.Escape("/") + "$", (Match m) => { return @"blob/" + m.Value; }); + result = result.Replace(@"https://raw.githubusercontent.com", @"https://github.com"); + result += rawUrl.Item2; + result += $"#L{lineNumber}"; + } + else + { + result = rawUrl.Item1 + rawUrl.Item2; + } + return result; + } + + public static string GetPDBLocation(ICallable callable) + { + try + { + string filename = System.IO.Path.ChangeExtension(callable.UnwrapCallable().GetType().Assembly.Location, ".pdb"); + if( File.Exists(filename) ) + { + return filename; + } + else + { + return null; + } + } + catch(NotSupportedException) + { + return null; + } + } + } + + public static class PortablePDBPathRemappingCache + { + [ThreadStatic] + private static Dictionary[]> knownPathRemappings = null; + + public static Tuple[] GetRemappingInfromation(string pdbLocation) + { + if (knownPathRemappings == null) + { + knownPathRemappings = new Dictionary[]>(); + } + + Tuple[] remappings; + if (knownPathRemappings.TryGetValue(pdbLocation, out remappings)) + { + return remappings; + } + else + { + try + { + string sourceLinkString = PortablePdbSymbolReader.GetSourceLinkString(pdbLocation); + remappings = PortablePdbSymbolReader.ParseSourceLinkString(sourceLinkString); + } + finally + { + knownPathRemappings.Add(pdbLocation, remappings); + } + return remappings; + } + } + + /// + /// Tuple of strings such that full URL consists of their concatenation. + /// First part of URL is URL root for all files in PDB and second part is relative path to given file. + /// + public static Tuple TryGetFileUrl(string pdbLocation, string fileName ) + { + if (fileName == null) return null; + + string prefix = null; + string rest = null; + + Tuple[] fileCorrespondence = GetRemappingInfromation(pdbLocation); + if (fileCorrespondence != null) + { + foreach (Tuple replacement in fileCorrespondence) + { + if (fileName.StartsWith(replacement.Item1)) + { + rest = fileName.Replace(replacement.Item1, ""); + prefix = replacement.Item2; + if (prefix.Contains(@"/") && rest.Contains(@"\")) + { + rest = rest.Replace(@"\", @"/"); + } + break; + } + } + } + return new Tuple(prefix,rest); + } + } + + public static class PortablePDBEmbeddedFilesCache + { + public const string lineMarkPrefix = ">>>"; + public const int lineNumberPaddingWidth = 6; + + [ThreadStatic] + private static Dictionary> embeddedFiles = null; + + public static Dictionary GetEmbeddedFiles(string pdbLocation) + { + if (embeddedFiles == null) + { + embeddedFiles = new Dictionary>(); + } + + Dictionary embeddedFilesFromPath = null; + if (embeddedFiles.TryGetValue(pdbLocation, out embeddedFilesFromPath)) + { + return embeddedFilesFromPath; + } + else + { + try + { + embeddedFilesFromPath = PortablePdbSymbolReader.GetEmbeddedFiles(pdbLocation); + } + finally + { + embeddedFiles.Add(pdbLocation, embeddedFilesFromPath); + } + return embeddedFilesFromPath; + } + } + + public static string GetEmbeddedFileRange( string pdbLocation, string fullName, int lineStart, int lineEnd, bool showLineNumbers = false, int markedLine = -1, string markPrefix = lineMarkPrefix) + { + Dictionary sourceToFile = GetEmbeddedFiles(pdbLocation); + if (sourceToFile == null) return null; + string source = sourceToFile.GetValueOrDefault(fullName); + if (source == null) return null; + string[] lines = Regex.Split(source, "\r\n|\r|\n"); + StringBuilder builder = new StringBuilder(); + for( int i = lineStart; i < (lineEnd == -1 ? int.MaxValue : lineEnd); ++i ) + { + if( showLineNumbers ) + { + builder.Append($"{i} ".PadLeft(lineNumberPaddingWidth)); + } + if (i == markedLine) + { + builder.Append(markPrefix); + } + builder.AppendLine(lines[i - 1]); + } + return builder.ToString(); + } + } +} \ No newline at end of file From 28ea1b8993ef121236a657b09d4e78ab5fbf8c79 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Tue, 29 Oct 2019 21:26:24 -0700 Subject: [PATCH 10/17] fixing code generation tests to have base one line numbers --- .../SimulationCodeTests.fs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs b/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs index 6139248ef3d..46a99b56d66 100644 --- a/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs +++ b/src/Simulation/CsharpGeneration.Tests/SimulationCodeTests.fs @@ -2304,10 +2304,10 @@ namespace N1 |> testOneClass randomAbstractOperation """ - [SourceLocation("%%%", OperationFunctor.Body, 107, 112)] - [SourceLocation("%%%", OperationFunctor.Adjoint, 112, 118)] - [SourceLocation("%%%", OperationFunctor.Controlled, 118, 125)] - [SourceLocation("%%%", OperationFunctor.ControlledAdjoint, 125, 131)] + [SourceLocation("%%%", OperationFunctor.Body, 108, 113)] + [SourceLocation("%%%", OperationFunctor.Adjoint, 113, 119)] + [SourceLocation("%%%", OperationFunctor.Controlled, 119, 126)] + [SourceLocation("%%%", OperationFunctor.ControlledAdjoint, 126, 132)] public partial class oneQubitOperation : Unitary, ICallable { public oneQubitOperation(IOperationFactory m) : base(m) @@ -2405,7 +2405,7 @@ namespace N1 |> testOneClass genCtrl3 """ - [SourceLocation("%%%", OperationFunctor.Body, 1265, 1271)] + [SourceLocation("%%%", OperationFunctor.Body, 1266, 1272)] public partial class composeImpl<__A__, __B__> : Operation<(ICallable,ICallable,__B__), QVoid>, ICallable { public composeImpl(IOperationFactory m) : base(m) @@ -2554,7 +2554,7 @@ namespace N1 |> testOneClass emptyFunction """ - [SourceLocation("%%%", OperationFunctor.Body, 32, 39)] + [SourceLocation("%%%", OperationFunctor.Body, 33, 40)] public partial class intFunction : Function, ICallable { public intFunction(IOperationFactory m) : base(m) @@ -2582,7 +2582,7 @@ namespace N1 |> testOneClass intFunction """ - [SourceLocation("%%%", OperationFunctor.Body, 44, 50)] + [SourceLocation("%%%", OperationFunctor.Body, 45, 51)] public partial class powFunction : Function<(Int64,Int64), Int64>, ICallable { public powFunction(IOperationFactory m) : base(m) @@ -2619,7 +2619,7 @@ namespace N1 |> testOneClass powFunction """ - [SourceLocation("%%%", OperationFunctor.Body, 50, 56)] + [SourceLocation("%%%", OperationFunctor.Body, 51, 57)] public partial class bigPowFunction : Function<(System.Numerics.BigInteger,Int64), System.Numerics.BigInteger>, ICallable { public bigPowFunction(IOperationFactory m) : base(m) @@ -3058,7 +3058,7 @@ using Microsoft.Quantum.Simulation.Core; #line hidden namespace Microsoft.Quantum.Tests.Inline { - [SourceLocation("%%%", OperationFunctor.Body, 6, -1)] + [SourceLocation("%%%", OperationFunctor.Body, 7, -1)] public partial class HelloWorld : Operation, ICallable { public HelloWorld(IOperationFactory m) : base(m) @@ -3104,7 +3104,7 @@ using Microsoft.Quantum.Simulation.Core; #line hidden namespace Microsoft.Quantum.Tests.LineNumbers { - [SourceLocation("%%%", OperationFunctor.Body, 8, -1)] + [SourceLocation("%%%", OperationFunctor.Body, 9, -1)] public partial class TestLineInBlocks : Operation, ICallable { public TestLineInBlocks(IOperationFactory m) : base(m) From 1701ba197062c475c6163c24ed41ce289cdeabbd Mon Sep 17 00:00:00 2001 From: Vadym Date: Wed, 30 Oct 2019 11:20:36 -0700 Subject: [PATCH 11/17] incorporating feedback --- src/Simulation/Common/PortablePDBReader.cs | 41 ++++++++++++++++------ 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Simulation/Common/PortablePDBReader.cs b/src/Simulation/Common/PortablePDBReader.cs index b7fbf3d2bbb..9c7ff0a9266 100644 --- a/src/Simulation/Common/PortablePDBReader.cs +++ b/src/Simulation/Common/PortablePDBReader.cs @@ -236,23 +236,44 @@ public static Dictionary GetEmbeddedFiles(string pdbLocation) public static string GetEmbeddedFileRange( string pdbLocation, string fullName, int lineStart, int lineEnd, bool showLineNumbers = false, int markedLine = -1, string markPrefix = lineMarkPrefix) { - Dictionary sourceToFile = GetEmbeddedFiles(pdbLocation); - if (sourceToFile == null) return null; - string source = sourceToFile.GetValueOrDefault(fullName); + Dictionary fileNameToFileSourceText = GetEmbeddedFiles(pdbLocation); + if (fileNameToFileSourceText == null) return null; + string source = fileNameToFileSourceText.GetValueOrDefault(fullName); if (source == null) return null; - string[] lines = Regex.Split(source, "\r\n|\r|\n"); + StringBuilder builder = new StringBuilder(); - for( int i = lineStart; i < (lineEnd == -1 ? int.MaxValue : lineEnd); ++i ) + using (StringReader reader = new StringReader(source)) { - if( showLineNumbers ) + int lineNumber = 0; + string currentLine = null; + + // first go through text source till we reach lineStart + while ( reader.Peek() != -1 ) { - builder.Append($"{i} ".PadLeft(lineNumberPaddingWidth)); + lineNumber++; + currentLine = reader.ReadLine(); + if (lineNumber == lineStart) + break; } - if (i == markedLine) + + while (reader.Peek() != -1) { - builder.Append(markPrefix); + if (showLineNumbers) + { + builder.Append($"{lineNumber} ".PadLeft(lineNumberPaddingWidth)); + } + if (lineNumber == markedLine) + { + builder.Append(markPrefix); + } + builder.AppendLine(currentLine); + + lineNumber++; + currentLine = reader.ReadLine(); + + if (lineNumber == lineEnd) + break; } - builder.AppendLine(lines[i - 1]); } return builder.ToString(); } From 6408fe2f6632e4e9d7a8c3895e4c8a45e27333be Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Wed, 30 Oct 2019 11:35:57 -0700 Subject: [PATCH 12/17] refactoring --- src/Simulation/Common/PortablePDBReader.cs | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Simulation/Common/PortablePDBReader.cs b/src/Simulation/Common/PortablePDBReader.cs index 9c7ff0a9266..4f094820a06 100644 --- a/src/Simulation/Common/PortablePDBReader.cs +++ b/src/Simulation/Common/PortablePDBReader.cs @@ -139,17 +139,17 @@ public static string GetPDBLocation(ICallable callable) public static class PortablePDBPathRemappingCache { [ThreadStatic] - private static Dictionary[]> knownPathRemappings = null; + private static Dictionary[]> pdbLocationToPathRemapping = null; public static Tuple[] GetRemappingInfromation(string pdbLocation) { - if (knownPathRemappings == null) + if (pdbLocationToPathRemapping == null) { - knownPathRemappings = new Dictionary[]>(); + pdbLocationToPathRemapping = new Dictionary[]>(); } Tuple[] remappings; - if (knownPathRemappings.TryGetValue(pdbLocation, out remappings)) + if (pdbLocationToPathRemapping.TryGetValue(pdbLocation, out remappings)) { return remappings; } @@ -162,7 +162,7 @@ public static Tuple[] GetRemappingInfromation(string pdbLocation } finally { - knownPathRemappings.Add(pdbLocation, remappings); + pdbLocationToPathRemapping.Add(pdbLocation, remappings); } return remappings; } @@ -206,17 +206,17 @@ public static class PortablePDBEmbeddedFilesCache public const int lineNumberPaddingWidth = 6; [ThreadStatic] - private static Dictionary> embeddedFiles = null; + private static Dictionary> pdbLocationToEmbeddedFiles = null; public static Dictionary GetEmbeddedFiles(string pdbLocation) { - if (embeddedFiles == null) + if (pdbLocationToEmbeddedFiles == null) { - embeddedFiles = new Dictionary>(); + pdbLocationToEmbeddedFiles = new Dictionary>(); } Dictionary embeddedFilesFromPath = null; - if (embeddedFiles.TryGetValue(pdbLocation, out embeddedFilesFromPath)) + if (pdbLocationToEmbeddedFiles.TryGetValue(pdbLocation, out embeddedFilesFromPath)) { return embeddedFilesFromPath; } @@ -228,7 +228,7 @@ public static Dictionary GetEmbeddedFiles(string pdbLocation) } finally { - embeddedFiles.Add(pdbLocation, embeddedFilesFromPath); + pdbLocationToEmbeddedFiles.Add(pdbLocation, embeddedFilesFromPath); } return embeddedFilesFromPath; } @@ -245,19 +245,19 @@ public static string GetEmbeddedFileRange( string pdbLocation, string fullName, using (StringReader reader = new StringReader(source)) { int lineNumber = 0; - string currentLine = null; // first go through text source till we reach lineStart while ( reader.Peek() != -1 ) { lineNumber++; - currentLine = reader.ReadLine(); if (lineNumber == lineStart) break; + reader.ReadLine(); } while (reader.Peek() != -1) { + string currentLine = reader.ReadLine(); if (showLineNumbers) { builder.Append($"{lineNumber} ".PadLeft(lineNumberPaddingWidth)); @@ -269,8 +269,6 @@ public static string GetEmbeddedFileRange( string pdbLocation, string fullName, builder.AppendLine(currentLine); lineNumber++; - currentLine = reader.ReadLine(); - if (lineNumber == lineEnd) break; } From 013bea670378c302dee0be4e2ba73f05eaa662c7 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Wed, 30 Oct 2019 15:14:30 -0700 Subject: [PATCH 13/17] refactoring --- src/Simulation/Common/StackTrace.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Simulation/Common/StackTrace.cs b/src/Simulation/Common/StackTrace.cs index 0dacf7d98cd..5d01999ca76 100644 --- a/src/Simulation/Common/StackTrace.cs +++ b/src/Simulation/Common/StackTrace.cs @@ -70,9 +70,11 @@ public string GetURLFromPDB() return PortablePdbSymbolReader.TryFormatGitHubUrl(result, failedLineNumber); } + private const string messageFormat = "in {0} on {1}"; + public override string ToString() { - return $"in {operation.FullName} on {sourceFile}:line {failedLineNumber}"; + return string.Format(messageFormat, operation.FullName, $"{sourceFile}:line {failedLineNumber}"); } /// @@ -99,7 +101,7 @@ public virtual string ToStringWithBestSourceLocation() } else { - return $"in {operation.FullName} on {url}"; + return string.Format(messageFormat, operation.FullName, url); } } } @@ -178,7 +180,7 @@ static StackFrame[] PopulateSourceLocations(Stack qsharpCallStack, S if (sourceLocation != null && sourceLocation.SpecializationKind == op.Variant) { currentFrame.sourceFile = System.IO.Path.GetFullPath(sourceLocation.SourceFile); - currentFrame.declarationStartLineNumber = sourceLocation.StartLine; // note that attribute has base 0 line numbers + currentFrame.declarationStartLineNumber = sourceLocation.StartLine; currentFrame.declarationEndLineNumber = sourceLocation.EndLine; } } From 12edebc8c8b7cc353eee44e56824d4e5d92d7823 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Wed, 30 Oct 2019 15:51:04 -0700 Subject: [PATCH 14/17] refactoring --- src/Simulation/Core/Generics/Adjoint.cs | 4 ++-- src/Simulation/Core/Generics/Controlled.cs | 4 ++-- src/Simulation/Core/Generics/GenericPartial.cs | 4 ++-- src/Simulation/Core/Operations/Adjoint.cs | 4 ++-- src/Simulation/Core/Operations/Controlled.cs | 4 ++-- src/Simulation/Core/Operations/Operation.cs | 2 +- src/Simulation/Core/Operations/OperationPartial.cs | 4 ++-- src/Simulation/Core/TypeExtensions.cs | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Simulation/Core/Generics/Adjoint.cs b/src/Simulation/Core/Generics/Adjoint.cs index 524df1feda1..45577250ebd 100644 --- a/src/Simulation/Core/Generics/Adjoint.cs +++ b/src/Simulation/Core/Generics/Adjoint.cs @@ -23,7 +23,7 @@ public interface IAdjointable : ICallable /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericAdjoint.DebuggerProxy))] - public class GenericAdjoint : GenericCallable, IApplyData, IWrappedOperation + public class GenericAdjoint : GenericCallable, IApplyData, IOperationWrapper { public GenericAdjoint(GenericCallable baseOp) : base(baseOp.Factory, null) { @@ -31,7 +31,7 @@ public GenericAdjoint(GenericCallable baseOp) : base(baseOp.Factory, null) } public GenericCallable BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; IEnumerable IApplyData.Qubits => ((IApplyData)this.BaseOp)?.Qubits; diff --git a/src/Simulation/Core/Generics/Controlled.cs b/src/Simulation/Core/Generics/Controlled.cs index 15f57783dfa..cc9b05fb994 100644 --- a/src/Simulation/Core/Generics/Controlled.cs +++ b/src/Simulation/Core/Generics/Controlled.cs @@ -25,7 +25,7 @@ public partial interface IControllable : ICallable /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericControlled.DebuggerProxy))] - public class GenericControlled : GenericCallable, IApplyData, IWrappedOperation + public class GenericControlled : GenericCallable, IApplyData, IOperationWrapper { public GenericControlled(GenericCallable baseOp) : base(baseOp.Factory, null) { @@ -33,7 +33,7 @@ public GenericControlled(GenericCallable baseOp) : base(baseOp.Factory, null) } public GenericCallable BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; IEnumerable IApplyData.Qubits => ((IApplyData)this.BaseOp)?.Qubits; diff --git a/src/Simulation/Core/Generics/GenericPartial.cs b/src/Simulation/Core/Generics/GenericPartial.cs index 3d8408d8ceb..8db1263639e 100644 --- a/src/Simulation/Core/Generics/GenericPartial.cs +++ b/src/Simulation/Core/Generics/GenericPartial.cs @@ -14,7 +14,7 @@ namespace Microsoft.Quantum.Simulation.Core /// input Type is not resolved until it gets Applied at runtime. /// [DebuggerTypeProxy(typeof(GenericPartial.DebuggerProxy))] - public class GenericPartial : GenericCallable, IApplyData, IWrappedOperation + public class GenericPartial : GenericCallable, IApplyData, IOperationWrapper { private Lazy __qubits = null; @@ -29,7 +29,7 @@ public GenericPartial(GenericCallable baseOp, object partialValues) : base(baseO } public GenericCallable BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; public override string Name => this.BaseOp.Name; public override string FullName => this.BaseOp.FullName; diff --git a/src/Simulation/Core/Operations/Adjoint.cs b/src/Simulation/Core/Operations/Adjoint.cs index 20bb62fc5fc..6db9f4a9f81 100644 --- a/src/Simulation/Core/Operations/Adjoint.cs +++ b/src/Simulation/Core/Operations/Adjoint.cs @@ -39,7 +39,7 @@ public Adjointable(IOperationFactory m) : base(m) /// Class used to represents an operation that has been adjointed. /// [DebuggerTypeProxy(typeof(AdjointedOperation<,>.DebuggerProxy))] - public class AdjointedOperation : Unitary, IApplyData, ICallable, IWrappedOperation + public class AdjointedOperation : Unitary, IApplyData, ICallable, IOperationWrapper { public AdjointedOperation(Operation op) : base(op.Factory) { @@ -50,7 +50,7 @@ public AdjointedOperation(Operation op) : base(op.Factory) } public Operation BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; public override void Init() { } diff --git a/src/Simulation/Core/Operations/Controlled.cs b/src/Simulation/Core/Operations/Controlled.cs index 1f7be787f66..8df3a8eb579 100644 --- a/src/Simulation/Core/Operations/Controlled.cs +++ b/src/Simulation/Core/Operations/Controlled.cs @@ -38,7 +38,7 @@ public Controllable(IOperationFactory m) : base(m) { } /// This class is used to represents an operation that has been controlled. /// [DebuggerTypeProxy(typeof(ControlledOperation<,>.DebuggerProxy))] - public class ControlledOperation : Unitary<(IQArray, I)>, IApplyData, ICallable, IWrappedOperation + public class ControlledOperation : Unitary<(IQArray, I)>, IApplyData, ICallable, IOperationWrapper { public class In : IApplyData { @@ -66,7 +66,7 @@ public ControlledOperation(Operation op) : base(op.Factory) } public Operation BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; public override void Init() { } diff --git a/src/Simulation/Core/Operations/Operation.cs b/src/Simulation/Core/Operations/Operation.cs index c654dc6b299..e81248f2528 100644 --- a/src/Simulation/Core/Operations/Operation.cs +++ b/src/Simulation/Core/Operations/Operation.cs @@ -22,7 +22,7 @@ public partial interface ICallable : ICallable /// , , /// , /// - public interface IWrappedOperation + public interface IOperationWrapper { ICallable BaseOperation { get; } } diff --git a/src/Simulation/Core/Operations/OperationPartial.cs b/src/Simulation/Core/Operations/OperationPartial.cs index 46b2407b616..12e03f01913 100644 --- a/src/Simulation/Core/Operations/OperationPartial.cs +++ b/src/Simulation/Core/Operations/OperationPartial.cs @@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Simulation.Core /// Optionally it can receive a Mapper to do the same. /// [DebuggerTypeProxy(typeof(OperationPartial<,,>.DebuggerProxy))] - public class OperationPartial : Operation, IUnitary

, IWrappedOperation + public class OperationPartial : Operation, IUnitary

, IOperationWrapper { private Lazy __qubits = null; @@ -59,7 +59,7 @@ public OperationPartial(Operation op, object partialTuple) : base(op.Facto public override void Init() { } public Operation BaseOp { get; } - ICallable IWrappedOperation.BaseOperation => BaseOp; + ICallable IOperationWrapper.BaseOperation => BaseOp; public Func Mapper { get; } diff --git a/src/Simulation/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs index 5bfb38c72eb..94bc5ebabf6 100644 --- a/src/Simulation/Core/TypeExtensions.cs +++ b/src/Simulation/Core/TypeExtensions.cs @@ -372,9 +372,9 @@ public static string QSharpType(this Type t) public static ICallable UnwrapCallable(this ICallable op) { ICallable res = op; - while (res as IWrappedOperation != null) + while (res as IOperationWrapper != null) { - res = (res as IWrappedOperation).BaseOperation; + res = (res as IOperationWrapper).BaseOperation; } return res; } From a981506fa614c17c356f2c4f6c43411130ccfce2 Mon Sep 17 00:00:00 2001 From: Alexander Vaschillo Date: Thu, 31 Oct 2019 17:11:58 -0700 Subject: [PATCH 15/17] Classical control --- src/Simulation/Common/IQuantumExecutor.cs | 330 +++++++++--------- src/Simulation/Common/Utils.cs | 5 +- .../Simulators/QuantumExecutor/Allocate.cs | 5 +- .../Simulators/QuantumExecutor/Assert.cs | 6 +- .../Simulators/QuantumExecutor/AssertProb.cs | 6 +- .../Simulators/QuantumExecutor/Borrow.cs | 5 +- .../QuantumExecutor/ClassicalControl.cs | 130 ++++++- .../QuantumExecutor/ClassicalControl.qs | 171 +++++---- .../Simulators/QuantumExecutor/Dump.cs | 7 +- .../QuantumExecutor/EmptyQuantumExecutor.cs | 12 +- .../Simulators/QuantumExecutor/Exp.cs | 8 +- .../Simulators/QuantumExecutor/ExpFrac.cs | 6 +- .../Simulators/QuantumExecutor/H.cs | 6 +- .../Simulators/QuantumExecutor/M.cs | 8 +- .../Simulators/QuantumExecutor/Measure.cs | 7 +- .../QuantumExecutorSimulator.cs | 4 +- .../Simulators/QuantumExecutor/R.cs | 6 +- .../Simulators/QuantumExecutor/R1.cs | 6 +- .../Simulators/QuantumExecutor/R1Frac.cs | 6 +- .../Simulators/QuantumExecutor/RFrac.cs | 6 +- .../Simulators/QuantumExecutor/Release.cs | 5 +- .../Simulators/QuantumExecutor/Reset.cs | 6 +- .../Simulators/QuantumExecutor/Return.cs | 5 +- .../Simulators/QuantumExecutor/S.cs | 6 +- .../Simulators/QuantumExecutor/SWAP.cs | 6 +- .../Simulators/QuantumExecutor/T.cs | 6 +- .../Simulators/QuantumExecutor/X.cs | 6 +- .../Simulators/QuantumExecutor/Y.cs | 6 +- .../Simulators/QuantumExecutor/Z.cs | 7 +- .../Simulators/QuantumExecutor/random.cs | 5 +- 30 files changed, 519 insertions(+), 279 deletions(-) diff --git a/src/Simulation/Common/IQuantumExecutor.cs b/src/Simulation/Common/IQuantumExecutor.cs index 935a217ed75..09c0c018e02 100644 --- a/src/Simulation/Common/IQuantumExecutor.cs +++ b/src/Simulation/Common/IQuantumExecutor.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor @@ -15,116 +18,98 @@ namespace Microsoft.Quantum.Simulation.QuantumExecutor public interface IQuantumExecutor { ///

- /// Called when Microsoft.Quantum.Intrinsic.R is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to . + /// Called when Microsoft.Quantum.Intrinsic.X is called in Q#. + /// In Q# the operation applies X gate to . The gate is given by matrix X=((0,1),(1,0)). /// /// - /// When adjoint of R is called in Q#, is called with replaced by -. + /// When adjoint of X is called in Q#, is called because X is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Pauli operator to be exponentiated to form the rotation. - /// Angle about which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void R(Pauli axis, double theta, Qubit qubit); + void X(Qubit qubit); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to controlled on . + /// Called when controlled Microsoft.Quantum.Intrinsic.X is called in Q#. + /// In Q# the operation applies X gate to controlled on . The gate is given by matrix X=((0,1),(1,0)). /// /// - /// When adjoint of Controlled R is called in Q#, is called with replaced by -. + /// When adjoint of Controlled X is called in Q#, is called because X is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Pauli operator to be exponentiated to form the rotation. - /// Angle about which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit); + void ControlledX(IQArray controls, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.RFrac is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . + /// Called when Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// In Q# the operation applies Y gate to . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). /// /// - /// When adjoint of RFrac is called in Q#, is called with replaced by -. + /// When adjoint of Y is called in Q#, is called because Y is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Pauli operator to be exponentiated to form the rotation. - /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void RFrac(Pauli axis, long numerator, long power, Qubit qubit); + void Y(Qubit qubit); /// - /// Called when a controlled Microsoft.Quantum.Intrinsic.RFrac is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . + /// Called when controlled Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// In Q# the operation applies X gate to controlled on . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). /// /// - /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. + /// When adjoint of Controlled Y is called in Q#, is called because Y is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Pauli operator to be exponentiated to form the rotation. - /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit); + void ControlledY(IQArray controls, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Exp is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to . + /// Called when Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// In Q# the operation applies Z gate to . The gate is given by matrix Z=((1,0),(0,-1)). /// /// - /// When adjoint of Exp is called in Q#, is called with replaced by -. + /// When adjoint of Z is called in Q#, is called because Z is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. - /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. - /// Register to apply the exponent to. - void Exp(IQArray paulis, double theta, IQArray qubits); + /// Qubit to which the gate should be applied. + void Z(Qubit qubit); /// - /// Called when a controlled Microsoft.Quantum.Intrinsic.Exp is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to controlled on . + /// Called when controlled Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// In Q# the operation applies Z gate to controlled on . The gate is given by matrix Z=((1,0),(0,-1)). /// /// - /// When adjoint of Controlled Exp is called in Q#, is called with replaced by -. + /// When adjoint of Controlled Z is called in Q#, is called because Z is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. - /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. - /// Register to apply the exponent to. - void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits); + /// Qubit to which the gate should be applied. + void ControlledZ(IQArray controls, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . + /// Called when Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states. /// /// - /// When adjoint of ExpFrac is called in Q#, is called with replaced by -. + /// When adjoint of SWAP is called in Q#, is called because SWAP is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. - /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. - /// Register to apply the exponent to. - void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits); + /// First qubit to be swapped. + /// Second qubit to be swapped. + void SWAP(Qubit qubit1, Qubit qubit2); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. - /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . + /// Called when controlled Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states controlled on . /// /// - /// When adjoint of Controlled ExpFrac is called in Q#, is called with replaced by -. + /// When adjoint of Controlled SWAP is called in Q#, is called because SWAP is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. - /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. - /// Register to apply the exponent to. - void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits); + /// First qubit to be swapped. + /// Second qubit to be swapped. + void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2); /// /// Called when Microsoft.Quantum.Intrinsic.H is called in Q#. @@ -211,7 +196,7 @@ public interface IQuantumExecutor /// In Q# the operation applies T gate to controlled on . The gate is given by matrix T=((1,0),(0,𝑒𝑥𝑝(𝑖⋅π/4))). /// /// - /// When adjoint of Controlled T is called in Q#, is called. + /// When adjoint of Controlled T is called in Q#, is called. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. @@ -242,210 +227,228 @@ public interface IQuantumExecutor void ControlledTAdj(IQArray controls, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.M is called in Q#. - /// In Q# the operation measures in Z basis, in other words in the computational basis. + /// Called when Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to . /// /// + /// When adjoint of R is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. - /// Class implementing interface can return any class derived from . /// + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. /// Qubit to which the gate should be applied. - /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. - Result M(Qubit qubit); + void R(Pauli axis, double theta, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Measure is called in Q#. - /// In Q# the operation measures multi-qubit Pauli observable given by on . + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(-𝑖⋅/2) to controlled on . /// /// + /// When adjoint of Controlled R is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. - /// Class implementing interface can return any class derived from . /// - /// Qubits to which the gate should be applied. - /// Array of single-qubit Pauli values describing multi-qubit Pauli observable. - /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. - Result Measure(IQArray bases, IQArray qubits); + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Reset is called in Q#. - /// In Q# the operation, measures and ensures it is in the |0⟩ state such that it can be safely released. + /// Called when Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . /// /// + /// When adjoint of RFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void Reset(Qubit qubit); + void RFrac(Pauli axis, long numerator, long power, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// Called when a controlled Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . /// /// + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. - /// A register on which to make the assertion. - /// The expected result of Measure(bases, qubits) - /// A message to be reported if the assertion fails. - void Assert(IQArray bases, IQArray qubits, Result result, string msg); - - /// - /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. - /// - /// - /// The names and the order of the parameters is similar to the corresponding Q# operation./ - /// - /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. - /// A register on which to make the assertion. - /// The probability with which result Zero is expected. - /// A message to be reported if the assertion fails. - /// The precision with which the probability of Zero outcome is specified. - void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol); + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.X is called in Q#. - /// In Q# the operation applies X gate to . The gate is given by matrix X=((0,1),(1,0)). + /// Called when Microsoft.Quantum.Intrinsic.R1 is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to . /// /// - /// When adjoint of X is called in Q#, is called because X is self-adjoint. + /// When adjoint of R1 is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// + /// Angle about which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void X(Qubit qubit); + void R1(double theta, Qubit qubit); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.X is called in Q#. - /// In Q# the operation applies X gate to controlled on . The gate is given by matrix X=((0,1),(1,0)). + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to controlled on . /// /// - /// When adjoint of Controlled X is called in Q#, is called because X is self-adjoint. + /// When adjoint of Controlled R1 is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. + /// Angle about which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void ControlledX(IQArray controls, Qubit qubit); + void ControlledR1(IQArray controls, double theta, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Y is called in Q#. - /// In Q# the operation applies Y gate to . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// Called when Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to . /// /// - /// When adjoint of Y is called in Q#, is called because Y is self-adjoint. + /// When adjoint of R1Frac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void Y(Qubit qubit); + void R1Frac(long numerator, long power, Qubit qubit); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.Y is called in Q#. - /// In Q# the operation applies X gate to controlled on . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// Called when a controlled Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to controlled on . /// /// - /// When adjoint of Controlled Y is called in Q#, is called because Y is self-adjoint. + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void ControlledY(IQArray controls, Qubit qubit); + void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit); /// - /// Called when Microsoft.Quantum.Intrinsic.Z is called in Q#. - /// In Q# the operation applies Z gate to . The gate is given by matrix Z=((1,0),(0,-1)). + /// Called when Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to . /// /// - /// When adjoint of Z is called in Q#, is called because Z is self-adjoint. + /// When adjoint of Exp is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Qubit to which the gate should be applied. - void Z(Qubit qubit); + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void Exp(IQArray paulis, double theta, IQArray qubits); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.Z is called in Q#. - /// In Q# the operation applies Z gate to controlled on . The gate is given by matrix Z=((1,0),(0,-1)). + /// Called when a controlled Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅) to controlled on . /// /// - /// When adjoint of Controlled Z is called in Q#, is called because Z is self-adjoint. + /// When adjoint of Controlled Exp is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Qubit to which the gate should be applied. - void ControlledZ(IQArray controls, Qubit qubit); + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits); /// - /// Called when Microsoft.Quantum.Intrinsic.R1 is called in Q#. - /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to . + /// Called when Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to . /// /// - /// When adjoint of R1 is called in Q#, is called with replaced by -. + /// When adjoint of ExpFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// Angle about which the qubit is to be rotated. - /// Qubit to which the gate should be applied. - void R1(double theta, Qubit qubit); + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. - /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) to controlled on . + /// Called when controlled Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// In Q# the operation applies 𝑒𝑥𝑝(𝑖⋅π⋅/2^) to controlled on . /// /// - /// When adjoint of Controlled R1 is called in Q#, is called with replaced by -. + /// When adjoint of Controlled ExpFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// /// The array of qubits on which the operation is controlled. - /// Angle about which the qubit is to be rotated. - /// Qubit to which the gate should be applied. - void ControlledR1(IQArray controls, double theta, Qubit qubit); + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits); /// - /// Called when Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. - /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to . + /// Called when Microsoft.Quantum.Intrinsic.M is called in Q#. + /// In Q# the operation measures in Z basis, in other words in the computational basis. /// /// - /// When adjoint of R1Frac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . /// - /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. /// Qubit to which the gate should be applied. - void R1Frac(long numerator, long power, Qubit qubit); + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result M(Qubit qubit); /// - /// Called when a controlled Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. - /// In Q# the operation applies gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) to controlled on . + /// Called when Microsoft.Quantum.Intrinsic.Measure is called in Q#. + /// In Q# the operation measures multi-qubit Pauli observable given by on . /// /// - /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . /// - /// The array of qubits on which the operation is controlled. - /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. - /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. - /// Qubit to which the gate should be applied. - void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit); + /// Qubits to which the gate should be applied. + /// Array of single-qubit Pauli values describing multi-qubit Pauli observable. + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result Measure(IQArray bases, IQArray qubits); /// - /// Called when Microsoft.Quantum.Intrinsic.SWAP is called in Q#. - /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states. + /// Called when Microsoft.Quantum.Intrinsic.Reset is called in Q#. + /// In Q# the operation, measures and ensures it is in the |0⟩ state such that it can be safely released. /// /// - /// When adjoint of SWAP is called in Q#, is called because SWAP is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// First qubit to be swapped. - /// Second qubit to be swapped. - void SWAP(Qubit qubit1, Qubit qubit2); + /// Qubit to which the gate should be applied. + void Reset(Qubit qubit); /// - /// Called when controlled Microsoft.Quantum.Intrinsic.SWAP is called in Q#. - /// In Q# the operation applies gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states controlled on . + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. /// /// - /// When adjoint of Controlled SWAP is called in Q#, is called because SWAP is self-adjoint. /// The names and the order of the parameters are the same as for the corresponding Q# operation. /// - /// The array of qubits on which the operation is controlled. - /// First qubit to be swapped. - /// Second qubit to be swapped. - void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2); + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The expected result of Measure(bases, qubits) + /// A message to be reported if the assertion fails. + void Assert(IQArray bases, IQArray qubits, Result result, string msg); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// + /// + /// The names and the order of the parameters is similar to the corresponding Q# operation./ + /// + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The probability with which result Zero is expected. + /// A message to be reported if the assertion fails. + /// The precision with which the probability of Zero outcome is specified. + void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol); /// /// Called before a call to any Q# operation. @@ -491,6 +494,19 @@ public interface IQuantumExecutor /// void ClassicallyControlled(Result measurementResult, Action onZero, Action onOne); + /// + /// Intended for a limited support of branching upon measurement results on a simulator level. + /// + /// The actual results of the measurements of a number of qubits upon which branching is to be performed. + /// The expected values of results of the measurements of these qubits. + /// Corresponds to quantum program that must be executed if all values are equal to corresponding + /// Corresponds to quantum program that must be executed if at least one of the values is not equal to a corresponding + /// + /// Calling onZero() will result in the execution of quantum program that Q# user intends to execute if result is . + /// The program is executed with the same instance of interface. + /// + void ClassicallyControlled(IQArray measurementResults, IQArray resultsValues, Action equalOp, Action nonEqualOp); + /// /// Called when qubits are allocated by Q# using block. /// diff --git a/src/Simulation/Common/Utils.cs b/src/Simulation/Common/Utils.cs index 6850ad7975d..04df6315d59 100644 --- a/src/Simulation/Common/Utils.cs +++ b/src/Simulation/Common/Utils.cs @@ -1,6 +1,7 @@ -using Microsoft.Quantum.Intrinsic; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using Microsoft.Quantum.Simulation.Core; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/Simulation/Simulators/QuantumExecutor/Allocate.cs b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs index 5f8c9c336ac..04ceba85113 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Allocate.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs @@ -1,4 +1,7 @@ -using Microsoft.Quantum.Simulation.Core; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor { diff --git a/src/Simulation/Simulators/QuantumExecutor/Assert.cs b/src/Simulation/Simulators/QuantumExecutor/Assert.cs index fef0b748262..64450284bb3 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Assert.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Assert.cs @@ -1,5 +1,7 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs b/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs index da8446aa8c8..1b283a44804 100644 --- a/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs +++ b/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs @@ -1,5 +1,7 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/Borrow.cs b/src/Simulation/Simulators/QuantumExecutor/Borrow.cs index 82d5062a4f1..0dbfe80e838 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Borrow.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Borrow.cs @@ -1,4 +1,7 @@ -using Microsoft.Quantum.Simulation.Core; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor { diff --git a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs index 11eb7bf8ac8..fee486af63f 100644 --- a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs +++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs @@ -1,7 +1,7 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor @@ -112,5 +112,127 @@ public class SimApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA return QVoid.Instance; }; } + + + + + + + + + + + + public class SimApplyConditionally : Extensions.ApplyConditionallyIntrinsic + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyConditionally(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, IQArray, ICallable, ICallable), QVoid> Body => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Apply(QVoid.Instance), + () => onNonEqualOp.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + } + + public class SimApplyConditionallyA : Extensions.ApplyConditionallyIntrinsicA + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyConditionallyA(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> Body => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Apply(QVoid.Instance), + () => onNonEqualOp.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> AdjointBody => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Adjoint.Apply(QVoid.Instance), + () => onNonEqualOp.Adjoint.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + } + + public class SimApplyConditionallyC : Extensions.ApplyConditionallyIntrinsicC + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyConditionallyC(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, IQArray, IControllable, IControllable), QVoid> Body => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Apply(QVoid.Instance), + () => onNonEqualOp.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> ControlledBody => //(q) => + (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Controlled.Apply(ctrls), + () => onNonEqualOp.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; + } + + public class SimApplyConditionallyCA : Extensions.ApplyConditionallyIntrinsicCA + { + private QuantumExecutorSimulator Simulator { get; } + + public SimApplyConditionallyCA(QuantumExecutorSimulator m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> Body => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Apply(QVoid.Instance), + () => onNonEqualOp.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> AdjointBody => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Adjoint.Apply(QVoid.Instance), + () => onNonEqualOp.Adjoint.Apply(QVoid.Instance)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Controlled.Apply(ctrls), + () => onNonEqualOp.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => //(q) => + (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Controlled.Adjoint.Apply(ctrls), + () => onNonEqualOp.Controlled.Adjoint.Apply(ctrls)); + return QVoid.Instance; + }; + } + } } diff --git a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs index 07bda4eb33c..f98b6e23c3a 100644 --- a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs +++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs @@ -1,41 +1,67 @@ -namespace Microsoft.Quantum.Simulation.QuantumExecutor.Extensions +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.QuantumExecutor.Extensions { open Microsoft.Quantum.Intrinsic; operation NoOp() : Unit is Ctl + Adj {} - operation Delay<'T> ( op : ('T => Unit), arg : 'T, aux : Unit ) : Unit { + + operation Delay<'T>(op : ('T => Unit), arg : 'T, aux : Unit) : Unit { op(arg); } - operation DelayC<'T> ( op : ('T => Unit is Ctl), arg : 'T, aux : Unit ) : Unit is Ctl { + operation DelayC<'T>(op : ('T => Unit is Ctl), arg : 'T, aux : Unit) : Unit is Ctl { op(arg); } - operation DelayA<'T> ( op : ('T => Unit is Adj), arg : 'T, aux : Unit ) : Unit is Adj { + operation DelayA<'T>(op : ('T => Unit is Adj), arg : 'T, aux : Unit) : Unit is Adj { op(arg); } - operation DelayCA<'T> ( op : ('T => Unit is Ctl + Adj), arg : 'T, aux : Unit ) : Unit is Ctl + Adj { + operation DelayCA<'T>(op : ('T => Unit is Ctl + Adj), arg : 'T, aux : Unit) : Unit is Ctl + Adj { op(arg); } - operation ApplyIfElseIntrinsic( measurementResult : Result, onResultZeroOp : (Unit => Unit) , onResultOneOp : (Unit => Unit) ) : Unit { + operation ApplyIfElseIntrinsic(measurementResult : Result, onResultZeroOp : (Unit => Unit) , onResultOneOp : (Unit => Unit)) : Unit { + body intrinsic; + } + + operation ApplyIfElseIntrinsicA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Adj) , onResultOneOp : (Unit => Unit is Adj)) : Unit { + body intrinsic; + adjoint intrinsic; + } + + operation ApplyIfElseIntrinsicC(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl)) : Unit { + body intrinsic; + controlled intrinsic; + } + + operation ApplyIfElseIntrinsicCA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj)) : Unit { + body intrinsic; + adjoint intrinsic; + controlled intrinsic; + controlled adjoint intrinsic; + } + + + operation ApplyConditionallyIntrinsic(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit) , onNonEqualOp : (Unit => Unit)) : Unit { body intrinsic; } - operation ApplyIfElseIntrinsicA( measurementResult : Result, onResultZeroOp : (Unit => Unit is Adj) , onResultOneOp : (Unit => Unit is Adj) ) : Unit { + operation ApplyConditionallyIntrinsicA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Adj) , onNonEqualOp : (Unit => Unit is Adj)) : Unit is Adj { body intrinsic; adjoint intrinsic; } - operation ApplyIfElseIntrinsicC( measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl) ) : Unit { + operation ApplyConditionallyIntrinsicC(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl) , onNonEqualOp : (Unit => Unit is Ctl)) : Unit is Ctl { body intrinsic; controlled intrinsic; } - operation ApplyIfElseIntrinsicCA( measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj) ) : Unit { + operation ApplyConditionallyIntrinsicCA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl + Adj) , onNonEqualOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { body intrinsic; adjoint intrinsic; controlled intrinsic; @@ -43,82 +69,103 @@ } - operation ApplyIfElse<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) , (onResultOneOp : ('U => Unit), oneArg : 'U) ) : Unit { - let zeroOp = Delay(onResultZeroOp,zeroArg,_); - let oneOp = Delay(onResultOneOp,oneArg,_); - ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + operation ApplyIfElseR<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) , (onResultOneOp : ('U => Unit), oneArg : 'U)) : Unit { + let zeroOp = Delay(onResultZeroOp, zeroArg, _); + let oneOp = Delay(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); } -// operation ApplyIfElseArray<'T,'U>( measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit), equalArg : 'T) , (onNonEqualOp : ('U => Unit), nonEqualArg : 'U) ) : Unit { -// let equalOp = Delay(onEqualOp,equalArg,_); -// let nonEqualOp = Delay(onNonEqualOp,nonEqualArg,_); // normalize spaces !!! -// //ApplyIfElseIntrinsic( measurementResults, resultsValues, equalOp, nonEqualOp ); // wrong!!! -// } + operation ApplyIfElseRA<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj), oneArg : 'U)) : Unit is Adj { + let zeroOp = DelayA(onResultZeroOp, zeroArg, _); + let oneOp = DelayA(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); + } - operation ApplyIfElseA<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj), oneArg : 'U) ) : Unit is Adj { - let zeroOp = DelayA(onResultZeroOp,zeroArg,_); - let oneOp = DelayA(onResultOneOp,oneArg,_); - ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + operation ApplyIfElseRC<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Ctl), oneArg : 'U)) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp, zeroArg, _); + let oneOp = DelayC(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); } - operation ApplyIfElseC<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Ctl), oneArg : 'U) ) : Unit is Ctl { - let zeroOp = DelayC(onResultZeroOp,zeroArg,_); - let oneOp = DelayC(onResultOneOp,oneArg,_); - ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + operation ApplyIfElseCA<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj + Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj + Ctl), oneArg : 'U)) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp, zeroArg, _); + let oneOp = DelayCA(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); } - operation ApplyIfElseCA<'T,'U>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj + Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj + Ctl), oneArg : 'U) ) : Unit is Ctl + Adj { - let zeroOp = DelayCA(onResultZeroOp,zeroArg,_); - let oneOp = DelayCA(onResultOneOp,oneArg,_); - ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + + operation ApplyIfZero<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T)) : Unit { + let zeroOp = Delay(onResultZeroOp, zeroArg, _); + let oneOp = Delay(NoOp, (), _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); } - operation ApplyIfZero<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) ) : Unit { - let zeroOp = Delay(onResultZeroOp,zeroArg,_); - let oneOp = Delay(NoOp, (),_); - ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + operation ApplyIfZeroA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T)) : Unit is Adj{ + let zeroOp = DelayA(onResultZeroOp, zeroArg, _); + let oneOp = DelayA(NoOp, (), _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); } - operation ApplyIfZeroA<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) ) : Unit is Adj{ - let zeroOp = DelayA(onResultZeroOp,zeroArg,_); - let oneOp = DelayA(NoOp, (),_); - ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + operation ApplyIfZeroC<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T)) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp, zeroArg, _); + let oneOp = DelayC(NoOp, (), _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); } - operation ApplyIfZeroC<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) ) : Unit is Ctl { - let zeroOp = DelayC(onResultZeroOp,zeroArg,_); - let oneOp = DelayC(NoOp, (),_); - ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + operation ApplyIfZeroCA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl + Adj), zeroArg : 'T)) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp, zeroArg, _); + let oneOp = DelayCA(NoOp, (), _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); } - operation ApplyIfZeroCA<'T>( measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl + Adj), zeroArg : 'T) ) : Unit is Ctl + Adj { - let zeroOp = DelayCA(onResultZeroOp,zeroArg,_); - let oneOp = DelayCA(NoOp, (),_); - ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + + operation ApplyIfOne<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit), oneArg : 'T)) : Unit { + let oneOp = Delay(onResultOneOp, oneArg, _); + let zeroOp = Delay(NoOp, (), _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); } - operation ApplyIfOne<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit), oneArg : 'T) ) : Unit { - let oneOp = Delay(onResultOneOp,oneArg,_); - let zeroOp = Delay(NoOp, (),_); - ApplyIfElseIntrinsic( measurementResult, zeroOp, oneOp ); + operation ApplyIfOneA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T)) : Unit is Adj { + let oneOp = DelayA(onResultOneOp, oneArg, _); + let zeroOp = DelayA(NoOp, (), _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfOneC<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T)) : Unit is Ctl { + let oneOp = DelayC(onResultOneOp, oneArg, _); + let zeroOp = DelayC(NoOp, (), _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfOneCA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl + Adj), oneArg : 'T)) : Unit is Ctl + Adj { + let oneOp = DelayCA(onResultOneOp, oneArg, _); + let zeroOp = DelayCA(NoOp, (), _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); + } + + + operation ApplyConditionally<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit), equalArg : 'T) , (onNonEqualOp : ('U => Unit), nonEqualArg : 'U)) : Unit { + let equalOp = Delay(onEqualOp,equalArg,_); + let nonEqualOp = Delay(onNonEqualOp,nonEqualArg,_); + ApplyConditionallyIntrinsic(measurementResults, resultsValues, equalOp, nonEqualOp); } - operation ApplyIfOneA<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T) ) : Unit is Adj { - let oneOp = DelayA(onResultOneOp,oneArg,_); - let zeroOp = DelayA(NoOp, (),_); - ApplyIfElseIntrinsicA( measurementResult, zeroOp, oneOp ); + operation ApplyConditionallyA<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Adj), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Adj), nonEqualArg : 'U)) : Unit is Adj { + let equalOp = DelayA(onEqualOp, equalArg, _); + let nonEqualOp = DelayA(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicA(measurementResults, resultsValues, equalOp, nonEqualOp); } - operation ApplyIfOneC<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T) ) : Unit is Ctl { - let oneOp = DelayC(onResultOneOp,oneArg,_); - let zeroOp = DelayC(NoOp, (),_); - ApplyIfElseIntrinsicC( measurementResult, zeroOp, oneOp ); + operation ApplyConditionallyC<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Ctl), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Ctl), nonEqualArg : 'U)) : Unit is Ctl { + let equalOp = DelayC(onEqualOp, equalArg, _); + let nonEqualOp = DelayC(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicC(measurementResults, resultsValues, equalOp, nonEqualOp); } - operation ApplyIfOneCA<'T>( measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl + Adj), oneArg : 'T) ) : Unit is Ctl + Adj { - let oneOp = DelayCA(onResultOneOp,oneArg,_); - let zeroOp = DelayCA(NoOp, (),_); - ApplyIfElseIntrinsicCA( measurementResult, zeroOp, oneOp ); + operation ApplyConditionallyCA<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Ctl + Adj), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Ctl + Adj), nonEqualArg : 'U)) : Unit is Ctl + Adj { + let equalOp = DelayCA(onEqualOp, equalArg, _); + let nonEqualOp = DelayCA(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicCA(measurementResults, resultsValues, equalOp, nonEqualOp); } } diff --git a/src/Simulation/Simulators/QuantumExecutor/Dump.cs b/src/Simulation/Simulators/QuantumExecutor/Dump.cs index ce7c997051a..749631d9f90 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Dump.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Dump.cs @@ -1,6 +1,7 @@ -using System; -using System.IO; -using System.Linq; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs index fc8636c69f7..ae88f95835d 100644 --- a/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs +++ b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs @@ -1,6 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor @@ -23,6 +24,11 @@ public virtual void ClassicallyControlled(Result measurementResult, Action onZer throw new NotImplementedException(); } + public virtual void ClassicallyControlled(IQArray measurementResults, IQArray resultsValues, Action equalOp, Action nonEqualOp) + { + throw new NotImplementedException(); + } + public virtual void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits) { throw new NotImplementedException(); diff --git a/src/Simulation/Simulators/QuantumExecutor/Exp.cs b/src/Simulation/Simulators/QuantumExecutor/Exp.cs index e809f9dce13..6d8469dd46b 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Exp.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Exp.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs b/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs index 7407a42ab99..865f4b3bc7b 100644 --- a/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs +++ b/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs @@ -1,7 +1,9 @@ -using Microsoft.Quantum.Simulation.Common; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; using System; -using System.Collections.Generic; namespace Microsoft.Quantum.Simulation.QuantumExecutor { diff --git a/src/Simulation/Simulators/QuantumExecutor/H.cs b/src/Simulation/Simulators/QuantumExecutor/H.cs index bea3fee8920..8cbd721019c 100644 --- a/src/Simulation/Simulators/QuantumExecutor/H.cs +++ b/src/Simulation/Simulators/QuantumExecutor/H.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/M.cs b/src/Simulation/Simulators/QuantumExecutor/M.cs index 573ddc3ebc9..49a613b9a47 100644 --- a/src/Simulation/Simulators/QuantumExecutor/M.cs +++ b/src/Simulation/Simulators/QuantumExecutor/M.cs @@ -1,7 +1,7 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/Measure.cs b/src/Simulation/Simulators/QuantumExecutor/Measure.cs index 6c8c2dd90d7..98f6a89ce4f 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Measure.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Measure.cs @@ -1,6 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs b/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs index bf1ad0cfe91..79270e6acf8 100644 --- a/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs +++ b/src/Simulation/Simulators/QuantumExecutor/QuantumExecutorSimulator.cs @@ -1,5 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; using Microsoft.Quantum.Simulation.Common; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/R.cs b/src/Simulation/Simulators/QuantumExecutor/R.cs index e58e03f7eb1..93a91a07221 100644 --- a/src/Simulation/Simulators/QuantumExecutor/R.cs +++ b/src/Simulation/Simulators/QuantumExecutor/R.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/R1.cs b/src/Simulation/Simulators/QuantumExecutor/R1.cs index b94bd038b40..1ae4d440caa 100644 --- a/src/Simulation/Simulators/QuantumExecutor/R1.cs +++ b/src/Simulation/Simulators/QuantumExecutor/R1.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs b/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs index de2e6f4f22f..54b26df4b22 100644 --- a/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs +++ b/src/Simulation/Simulators/QuantumExecutor/R1Frac.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/RFrac.cs b/src/Simulation/Simulators/QuantumExecutor/RFrac.cs index 27d9955154f..cc7fef265d2 100644 --- a/src/Simulation/Simulators/QuantumExecutor/RFrac.cs +++ b/src/Simulation/Simulators/QuantumExecutor/RFrac.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Common; using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/Release.cs b/src/Simulation/Simulators/QuantumExecutor/Release.cs index 4447c365f86..4aa94ffa091 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Release.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Release.cs @@ -1,4 +1,7 @@ -using Microsoft.Quantum.Simulation.Core; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor { diff --git a/src/Simulation/Simulators/QuantumExecutor/Reset.cs b/src/Simulation/Simulators/QuantumExecutor/Reset.cs index 6c655d06e1b..3daec9ebb82 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Reset.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Reset.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/Return.cs b/src/Simulation/Simulators/QuantumExecutor/Return.cs index cdeeb859aa6..743ddfeb8d8 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Return.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Return.cs @@ -1,4 +1,7 @@ -namespace Microsoft.Quantum.Simulation.QuantumExecutor +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.QuantumExecutor { using Microsoft.Quantum.Simulation.Core; diff --git a/src/Simulation/Simulators/QuantumExecutor/S.cs b/src/Simulation/Simulators/QuantumExecutor/S.cs index 510867fd758..1d8812df8d7 100644 --- a/src/Simulation/Simulators/QuantumExecutor/S.cs +++ b/src/Simulation/Simulators/QuantumExecutor/S.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/SWAP.cs b/src/Simulation/Simulators/QuantumExecutor/SWAP.cs index 8aeb05eefdc..7b96ecf6e73 100644 --- a/src/Simulation/Simulators/QuantumExecutor/SWAP.cs +++ b/src/Simulation/Simulators/QuantumExecutor/SWAP.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/T.cs b/src/Simulation/Simulators/QuantumExecutor/T.cs index 06e650b6056..55ecdfde021 100644 --- a/src/Simulation/Simulators/QuantumExecutor/T.cs +++ b/src/Simulation/Simulators/QuantumExecutor/T.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/X.cs b/src/Simulation/Simulators/QuantumExecutor/X.cs index 4bcb59e4f5b..a65e19d62b0 100644 --- a/src/Simulation/Simulators/QuantumExecutor/X.cs +++ b/src/Simulation/Simulators/QuantumExecutor/X.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/Y.cs b/src/Simulation/Simulators/QuantumExecutor/Y.cs index 89e37c6f1a1..bc64eb27500 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Y.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Y.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/Z.cs b/src/Simulation/Simulators/QuantumExecutor/Z.cs index 8a37d2999b3..2e7c3646e71 100644 --- a/src/Simulation/Simulators/QuantumExecutor/Z.cs +++ b/src/Simulation/Simulators/QuantumExecutor/Z.cs @@ -1,6 +1,7 @@ -using System; -using System.Runtime.InteropServices; -using Microsoft.Quantum.Intrinsic; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.QuantumExecutor diff --git a/src/Simulation/Simulators/QuantumExecutor/random.cs b/src/Simulation/Simulators/QuantumExecutor/random.cs index 4f10b3a1e68..38350175bad 100644 --- a/src/Simulation/Simulators/QuantumExecutor/random.cs +++ b/src/Simulation/Simulators/QuantumExecutor/random.cs @@ -1,4 +1,7 @@ -using Microsoft.Quantum.Simulation.Core; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; using System; namespace Microsoft.Quantum.Simulation.QuantumExecutor From d464610ef6f4c02804dc4643f48f1c3acfa2dbdb Mon Sep 17 00:00:00 2001 From: Alexander Vaschillo Date: Fri, 1 Nov 2019 13:21:02 -0700 Subject: [PATCH 16/17] Cleanup --- src/Simulation/Common/IQuantumExecutor.cs | 3 +- .../QuantumExecutor/ClassicalControl.cs | 108 +++++++++--------- .../QuantumExecutor/EmptyQuantumExecutor.cs | 3 +- 3 files changed, 54 insertions(+), 60 deletions(-) diff --git a/src/Simulation/Common/IQuantumExecutor.cs b/src/Simulation/Common/IQuantumExecutor.cs index 09c0c018e02..3c9d1236250 100644 --- a/src/Simulation/Common/IQuantumExecutor.cs +++ b/src/Simulation/Common/IQuantumExecutor.cs @@ -7,8 +7,7 @@ namespace Microsoft.Quantum.Simulation.QuantumExecutor { /// - /// An interface for implementing QDK target machines which work - /// on a quantum circuit level. + /// An interface for implementing QDK target machines that work on a quantum circuit level. /// It is intended to be used with . /// /// diff --git a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs index fee486af63f..4320d0995b5 100644 --- a/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs +++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs @@ -17,8 +17,9 @@ public class SimApplyIfElse : Extensions.ApplyIfElseIntrinsic public override Func<(Result, ICallable, ICallable), QVoid> Body => (q) => { var (measurementResult, onZero, onOne) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), - () => onOne.Apply(QVoid.Instance)); + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); return QVoid.Instance; }; } @@ -32,8 +33,9 @@ public class SimApplyIfElseA : Extensions.ApplyIfElseIntrinsicA public override Func<(Result, IAdjointable, IAdjointable), QVoid> Body => (q) => { var (measurementResult, onZero, onOne) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), - () => onOne.Apply(QVoid.Instance)); + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); return QVoid.Instance; }; @@ -41,8 +43,8 @@ public class SimApplyIfElseA : Extensions.ApplyIfElseIntrinsicA { var (measurementResult, onZero, onOne) = q; Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, - () => onZero.Adjoint.Apply(QVoid.Instance), - () => onOne.Adjoint.Apply(QVoid.Instance)); + () => onZero.Adjoint.Apply(QVoid.Instance), + () => onOne.Adjoint.Apply(QVoid.Instance)); return QVoid.Instance; }; } @@ -56,19 +58,20 @@ public class SimApplyIfElseC : Extensions.ApplyIfElseIntrinsicC public override Func<(Result, IControllable, IControllable), QVoid> Body => (q) => { var (measurementResult, onZero, onOne) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), - () => onOne.Apply(QVoid.Instance)); + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); return QVoid.Instance; }; - public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> ControlledBody => - (q) => - { - var (ctrls, (measurementResult, onZero, onOne)) = q; - Simulator.QuantumExecutor.ClassicallyControlled( - measurementResult, () => onZero.Controlled.Apply(ctrls), () => onOne.Controlled.Apply(ctrls)); - return QVoid.Instance; - }; + public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Controlled.Apply(ctrls), + () => onOne.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; } public class SimApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA @@ -80,8 +83,9 @@ public class SimApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA public override Func<(Result, IUnitary, IUnitary), QVoid> Body => (q) => { var (measurementResult, onZero, onOne) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Apply(QVoid.Instance), - () => onOne.Apply(QVoid.Instance)); + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Apply(QVoid.Instance), + () => onOne.Apply(QVoid.Instance)); return QVoid.Instance; }; @@ -89,40 +93,32 @@ public class SimApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA { var (measurementResult, onZero, onOne) = q; Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, - () => onZero.Adjoint.Apply(QVoid.Instance), - () => onOne.Adjoint.Apply(QVoid.Instance)); + () => onZero.Adjoint.Apply(QVoid.Instance), + () => onOne.Adjoint.Apply(QVoid.Instance)); return QVoid.Instance; }; public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledBody => (q) => { var (ctrls, (measurementResult, onZero, onOne)) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, () => onZero.Controlled.Apply(ctrls), - () => onOne.Controlled.Apply(ctrls)); + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Controlled.Apply(ctrls), + () => onOne.Controlled.Apply(ctrls)); return QVoid.Instance; }; - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => - (q) => - { - var (ctrls, (measurementResult, onZero, onOne)) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, - () => onZero.Controlled.Adjoint.Apply(ctrls), - () => onOne.Controlled.Adjoint.Apply(ctrls)); - return QVoid.Instance; - }; + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResult, + () => onZero.Controlled.Adjoint.Apply(ctrls), + () => onOne.Controlled.Adjoint.Apply(ctrls)); + return QVoid.Instance; + }; } - - - - - - - - public class SimApplyConditionally : Extensions.ApplyConditionallyIntrinsic { private QuantumExecutorSimulator Simulator { get; } @@ -179,15 +175,14 @@ public class SimApplyConditionallyC : Extensions.ApplyConditionallyIntrinsicC return QVoid.Instance; }; - public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> ControlledBody => //(q) => - (q) => - { - var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, - () => onEqualOp.Controlled.Apply(ctrls), - () => onNonEqualOp.Controlled.Apply(ctrls)); - return QVoid.Instance; - }; + public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Controlled.Apply(ctrls), + () => onNonEqualOp.Controlled.Apply(ctrls)); + return QVoid.Instance; + }; } public class SimApplyConditionallyCA : Extensions.ApplyConditionallyIntrinsicCA @@ -223,15 +218,14 @@ public class SimApplyConditionallyCA : Extensions.ApplyConditionallyIntrinsicCA return QVoid.Instance; }; - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => //(q) => - (q) => - { - var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; - Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, - () => onEqualOp.Controlled.Adjoint.Apply(ctrls), - () => onNonEqualOp.Controlled.Adjoint.Apply(ctrls)); - return QVoid.Instance; - }; + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + Simulator.QuantumExecutor.ClassicallyControlled(measurementResults, resultsValues, + () => onEqualOp.Controlled.Adjoint.Apply(ctrls), + () => onNonEqualOp.Controlled.Adjoint.Apply(ctrls)); + return QVoid.Instance; + }; } } diff --git a/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs index ae88f95835d..8b897d4d072 100644 --- a/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs +++ b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs @@ -7,7 +7,8 @@ namespace Microsoft.Quantum.Simulation.QuantumExecutor { /// - /// An example of IQuantumExecutor that throws for every call. + /// A class that implements IQuantumExecutor that does not do any logic, but is convenient to inherit from. + /// It throws for most APIs. /// class EmptyQuantumExecutor : IQuantumExecutor { From c5f6e961ef727c48ece1b511143ffcdca14b0a95 Mon Sep 17 00:00:00 2001 From: Vadym Kliuchnikov Date: Mon, 11 Nov 2019 21:00:56 -0800 Subject: [PATCH 17/17] bumping compiler version --- .../CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj index 749698bd81e..296cb60026c 100644 --- a/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj +++ b/src/Simulation/CsharpGeneration/Microsoft.Quantum.CsharpGeneration.fsproj @@ -18,7 +18,7 @@ - +