: ICallable
ICallable Partial
(Func
mapper);
}
-
+ ///
+ /// An operation that wraps another operation, for example
+ /// , ,
+ /// ,
+ ///
+ public interface IOperationWrapper
+ {
+ 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..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
+ public class OperationPartial
: Operation
, IUnitary
, IOperationWrapper
{
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 IOperationWrapper.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/Core/TypeExtensions.cs b/src/Simulation/Core/TypeExtensions.cs
index 9822b37f373..94bc5ebabf6 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 IOperationWrapper != null)
+ {
+ res = (res as IOperationWrapper).BaseOperation;
+ }
+ return res;
+ }
}
}
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 @@
-
+
diff --git a/src/Simulation/Simulators.Tests/Circuits/Fail.qs b/src/Simulation/Simulators.Tests/Circuits/Fail.qs
index 3fb9302255c..4d20fdea39c 100644
--- a/src/Simulation/Simulators.Tests/Circuits/Fail.qs
+++ b/src/Simulation/Simulators.Tests/Circuits/Fail.qs
@@ -3,10 +3,75 @@
namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits {
- operation AlwaysFail() : Unit {
- fail "Always fail";
+ operation AlwaysFail() : Unit is Adj + Ctl{
+ 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);
+ }
+
+ 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));
+ }
+
+ 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
new file mode 100644
index 00000000000..602b9fff854
--- /dev/null
+++ b/src/Simulation/Simulators.Tests/StackTraceTests.cs
@@ -0,0 +1,314 @@
+// 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;
+using System.Text;
+
+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;
+
+ 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);
+
+ 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());
+ }
+ }
+ }
+
+ [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;
+
+ 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);
+ }
+ }
+
+ {
+ StackTraceCollector sc = new StackTraceCollector(sim);
+ ICallable op = sim.Get();
+ try
+ {
+ QVoid res = op.Apply(QVoid.Instance);
+ }
+ catch (ExecutionFailException)
+ {
+ StackFrame[] stackFrames = sc.CallStack;
+
+ 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(6, stackFrames[0].failedLineNumber);
+ Assert.Equal(24, 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;
+
+ 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(6, stackFrames[0].failedLineNumber);
+ Assert.Equal(24, stackFrames[1].failedLineNumber);
+ Assert.Equal(56, stackFrames[2].failedLineNumber);
+ }
+ }
+ }
+
+ [Fact]
+ public void PartialFail1Test()
+ {
+ 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(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);
+ }
+ }
+
+ {
+ StackTraceCollector sc = new StackTraceCollector(sim);
+ ICallable op = sim.Get();
+ try
+ {
+ QVoid res = op.Apply(QVoid.Instance);
+ }
+ catch (ExecutionFailException)
+ {
+ StackFrame[] stackFrames = sc.CallStack;
+
+ 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(6, stackFrames[0].failedLineNumber);
+ Assert.Equal(32, stackFrames[1].failedLineNumber);
+ Assert.Equal(43, 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;
+
+ 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(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);
+ }
+ }
+ }
+
+ [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
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
diff --git a/src/Simulation/Simulators/QuantumExecutor/Allocate.cs b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs
new file mode 100644
index 00000000000..04ceba85113
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/Allocate.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+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..64450284bb3
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/Assert.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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..1b283a44804
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/AssertProb.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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..0dbfe80e838
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/Borrow.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+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..4320d0995b5
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.cs
@@ -0,0 +1,232 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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;
+ };
+ }
+
+
+
+ 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) =>
+ {
+ 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) =>
+ {
+ 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
new file mode 100644
index 00000000000..f98b6e23c3a
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/ClassicalControl.qs
@@ -0,0 +1,171 @@
+// 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 {
+ 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 ApplyConditionallyIntrinsic(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit) , onNonEqualOp : (Unit => Unit)) : Unit {
+ body intrinsic;
+ }
+
+ operation ApplyConditionallyIntrinsicA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Adj) , onNonEqualOp : (Unit => Unit is Adj)) : Unit is Adj {
+ body intrinsic;
+ adjoint intrinsic;
+ }
+
+ operation ApplyConditionallyIntrinsicC(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl) , onNonEqualOp : (Unit => Unit is Ctl)) : Unit is Ctl {
+ body intrinsic;
+ controlled intrinsic;
+ }
+
+ 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;
+ controlled adjoint intrinsic;
+ }
+
+
+ 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 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 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 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);
+ }
+
+
+ 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 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 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 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
new file mode 100644
index 00000000000..749631d9f90
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/Dump.cs
@@ -0,0 +1,68 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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..8b897d4d072
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/EmptyQuantumExecutor.cs
@@ -0,0 +1,238 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Microsoft.Quantum.Simulation.Core;
+
+namespace Microsoft.Quantum.Simulation.QuantumExecutor
+{
+ ///
+ /// 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
+ {
+ 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 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();
+ }
+
+ 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..6d8469dd46b
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/Exp.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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..865f4b3bc7b
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/ExpFrac.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Quantum.Simulation.Common;
+using Microsoft.Quantum.Simulation.Core;
+using System;
+
+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..8cbd721019c
--- /dev/null
+++ b/src/Simulation/Simulators/QuantumExecutor/H.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+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