diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index d45a296b737..143313aa57e 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -5,7 +5,7 @@ on: pull_request: # Note that we only support automerge on branches that have required checks. branches: - - master + - main - feature/* types: - labeled @@ -19,7 +19,7 @@ on: pull_request_review: # Note that we only support automerge on branches that have required checks. branches: - - master + - main - feature/* types: - submitted diff --git a/.github/workflows/qdk-sync.yml b/.github/workflows/qdk-sync.yml new file mode 100644 index 00000000000..26b4da3d7d6 --- /dev/null +++ b/.github/workflows/qdk-sync.yml @@ -0,0 +1,28 @@ +name: Sync QDK repos + +on: + push: + branches: + - main + +jobs: + sync-repos: + runs-on: ubuntu-latest + steps: + - name: Login to Azure + uses: Azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - id: AzureKeyVault + uses: Azure/get-keyvault-secrets@v1.0 + with: + keyvault: 'kv-qdk-build' + secrets: 'qdkBuildPAT' + + - name: 'Trigger QDK sync build' + uses: Azure/pipelines@releases/v1 + with: + azure-devops-project-url: 'https://dev.azure.com/ms-quantum-public/Microsoft Quantum (public)' + azure-pipeline-name: 'microsoft.qdk.sync' + azure-devops-token: ${{ steps.AzureKeyVault.outputs.qdkBuildPAT }} diff --git a/README.md b/README.md index d20ed0093ae..1cc7621c6cd 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ You may also visit our [Quantum](https://github.com/microsoft/quantum) repositor ## Building from Source ## -[![Build Status](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_apis/build/status/microsoft.qsharp-runtime?branchName=master)](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_build/latest?definitionId=15&branchName=master) +[![Build Status](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_apis/build/status/microsoft.qsharp-runtime?branchName=main)](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_build/latest?definitionId=15&branchName=main) Note that when building from source, this repository is configured so that .NET Core will automatically look at the [Quantum Development Kit prerelease feed](https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_packaging?_a=feed&feed=alpha) in addition to any other feeds you may have configured. diff --git a/build/ci.yml b/build/ci.yml index b274f861d26..b194fa64afd 100644 --- a/build/ci.yml +++ b/build/ci.yml @@ -1,6 +1,12 @@ name: $(Build.Major).$(Build.Minor).$(date:yyMM).$(DayOfMonth)$(rev:rr) -trigger: -- master + +trigger: none + +pr: +- main +- feature/* +- features/* +- release/* variables: Build.Major: 0 @@ -28,4 +34,4 @@ jobs: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' inputs: - failOnAlert: true \ No newline at end of file + failOnAlert: true diff --git a/build/e2e.yml b/build/e2e.yml new file mode 100644 index 00000000000..1a56ac89ab3 --- /dev/null +++ b/build/e2e.yml @@ -0,0 +1,33 @@ +name: $(Build.Major).$(Build.Minor).$(date:yyMM).$(BuildId) + +parameters: +- name: validation_level + displayName: Validation Level + type: string + default: normal + values: + - minimal + - normal + - full + +trigger: none + +pr: +- main +- feature/* +- features/* +- release/* + +resources: + repositories: + - repository: qdk + type: github + endpoint: github + name: microsoft/qdk + ref: refs/heads/main + +extends: + template: build/qdk-module-e2e.yml@qdk + parameters: + module: qsharp-runtime + validation_level: ${{ parameters.validation_level }} diff --git a/src/Azure/Azure.Quantum.Client/Exceptions/WorkspaceClientException.cs b/src/Azure/Azure.Quantum.Client/Exceptions/WorkspaceClientException.cs index 48381424b03..821e3a64bc2 100644 --- a/src/Azure/Azure.Quantum.Client/Exceptions/WorkspaceClientException.cs +++ b/src/Azure/Azure.Quantum.Client/Exceptions/WorkspaceClientException.cs @@ -66,7 +66,8 @@ public WorkspaceClientException( $"ResourceGroupName: {resourceGroupName}{Environment.NewLine}" + $"WorkspaceName: {workspaceName}{Environment.NewLine}" + $"BaseUri: {baseUri}{Environment.NewLine}" + - $"JobId: {jobId}", + $"JobId: {jobId}{Environment.NewLine}" + + (inner != null ? $"Inner Exception: {inner}" : string.Empty), inner) { } diff --git a/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs b/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs index fd709cee94e..cd61dd5ce49 100644 --- a/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs +++ b/src/Azure/Azure.Quantum.Client/Machine/QuantumMachineFactory.cs @@ -23,6 +23,8 @@ public static class QuantumMachineFactory var machineName = targetName is null ? null + : targetName.StartsWith("qci.") + ? "Microsoft.Quantum.Providers.QCI.Targets.QCIQuantumMachine, Microsoft.Quantum.Providers.QCI" : targetName.StartsWith("ionq.") ? "Microsoft.Quantum.Providers.IonQ.Targets.IonQQuantumMachine, Microsoft.Quantum.Providers.IonQ" : targetName.StartsWith("honeywell.") diff --git a/src/Simulation/Common/AbstractFactory.cs b/src/Simulation/Common/AbstractFactory.cs index 204936002ee..fc5430288d4 100644 --- a/src/Simulation/Common/AbstractFactory.cs +++ b/src/Simulation/Common/AbstractFactory.cs @@ -3,9 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; - -using Microsoft.Quantum.Simulation.Core; namespace Microsoft.Quantum.Simulation.Common { @@ -18,8 +15,8 @@ namespace Microsoft.Quantum.Simulation.Common /// public abstract class AbstractFactory { - private Dictionary opsOverrides = new Dictionary(); - private Dictionary opsCache = new Dictionary(); + protected Dictionary opsOverrides = new Dictionary(); + protected Dictionary opsCache = new Dictionary(); /// /// Register an override for the given operation. diff --git a/src/Simulation/Common/Exceptions/QuantumProcessorTranslationException.cs b/src/Simulation/Common/Exceptions/TranslationException.cs similarity index 100% rename from src/Simulation/Common/Exceptions/QuantumProcessorTranslationException.cs rename to src/Simulation/Common/Exceptions/TranslationException.cs diff --git a/src/Simulation/Common/OperationException.cs b/src/Simulation/Common/OperationException.cs new file mode 100644 index 00000000000..ab4d7e6d177 --- /dev/null +++ b/src/Simulation/Common/OperationException.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; + +#nullable enable + +namespace Microsoft.Quantum.Simulation.Common +{ + /// + /// A class that implements exception to be thrown when Operation is not supported. + /// + public class UnsupportedOperationException : PlatformNotSupportedException + { + public UnsupportedOperationException(string text = "", + [CallerFilePath] string file = "", + [CallerMemberName] string member = "", + [CallerLineNumber] int line = 0) + : base($"{file}::{line}::[{member}]:{text}") + { + } + } + +} \ No newline at end of file diff --git a/src/Simulation/Common/QuantumProcessorBase.cs b/src/Simulation/Common/QuantumProcessorBase.cs index 26783f7fdea..fd9043f8a12 100644 --- a/src/Simulation/Common/QuantumProcessorBase.cs +++ b/src/Simulation/Common/QuantumProcessorBase.cs @@ -2,9 +2,8 @@ // Licensed under the MIT License. using System; +using System.Linq; using Microsoft.Quantum.Simulation.Core; -using System.Diagnostics; -using System.Runtime.CompilerServices; namespace Microsoft.Quantum.Simulation.Common { @@ -179,37 +178,16 @@ public virtual void Reset(Qubit qubit) throw new UnsupportedOperationException(); } - public virtual long StartConditionalStatement(IQArray measurementResults, IQArray resultsValues) + public virtual long StartConditionalStatement(IQArray results1, IQArray results2) { - if (measurementResults == null) { return 1; }; - if (resultsValues == null) { return 1; }; - Debug.Assert(measurementResults.Count == resultsValues.Count); - if (measurementResults.Count != resultsValues.Count) { return 1; }; - - int equal = 1; - - for (int i = 0; i < measurementResults.Count; i++) - { - if (measurementResults[i] != resultsValues[i]) - { - equal = 0; - } - } - - return equal; + if (results1 == null) { return results2 == null ? 1 : 0; }; + if (results1.Count != results2?.Count) { return 0; }; + return results1.Zip(results2, (r1, r2) => (r1, r2)).Any(pair => pair.r1 != pair.r2) ? 0 : 1; } - public virtual long StartConditionalStatement(Result measurementResult, Result resultValue) + public virtual long StartConditionalStatement(Result result1, Result result2) { - - if (measurementResult == resultValue) - { - return 1; - } - else - { - return 0; - } + return result1 == result2 ? 1 : 0; } public virtual bool RunThenClause(long statement) @@ -234,7 +212,6 @@ public virtual bool RepeatElseClause(long statement) public virtual void EndConditionalStatement(long id) { - } public virtual void Assert(IQArray bases, IQArray qubits, Result result, string msg) @@ -286,18 +263,4 @@ public virtual void OnMessage(string msg) } } - - /// - /// A class that implements exception to be thrown when Operation is not supported by a QuantumProcessor. - /// - public class UnsupportedOperationException : PlatformNotSupportedException - { - public UnsupportedOperationException(string text = "", - [CallerFilePath] string file = "", - [CallerMemberName] string member = "", - [CallerLineNumber] int line = 0) - : base($"{file}::{line}::[{member}]:{text}") - { - } - } } diff --git a/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs b/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs index 158dd4dabf6..bccc4e6a815 100644 --- a/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs +++ b/src/Simulation/Simulators/QCTraceSimulator/Circuits/Interface.qs @@ -77,5 +77,4 @@ namespace Microsoft.Quantum.Simulation.Simulators.QCTraceSimulators.Implementati operation ForceMeasure (observable : Pauli[], target : Qubit[], result : Result) : Unit { body intrinsic; } - } diff --git a/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulator.ClassicalControl.cs b/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulator.ClassicalControl.cs deleted file mode 100644 index 125b86106f3..00000000000 --- a/src/Simulation/Simulators/QCTraceSimulator/QCTraceSimulator.ClassicalControl.cs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.IO; -using Microsoft.Quantum.Simulation.Core; - -namespace Microsoft.Quantum.Simulation.Simulators.QCTraceSimulators.Implementation -{ - public partial class QCTraceSimulatorImpl - { - #region Static Methods - - /// - /// Runs the given functor of the given operation with the given control qubits. - /// - private static void RunClause(ICallable op, OperationFunctor type, IQArray? ctrls) - { - switch (type) - { - case OperationFunctor.Body: op.Apply(QVoid.Instance); break; - case OperationFunctor.Adjoint: ((IAdjointable)op).Adjoint.Apply(QVoid.Instance); break; - case OperationFunctor.Controlled: ((IControllable)op).Controlled.Apply((ctrls, QVoid.Instance)); break; - case OperationFunctor.ControlledAdjoint: ((IUnitary)op).Controlled.Adjoint.Apply((ctrls, QVoid.Instance)); break; - } - } - - /// - /// This is a wrapper for an if-statement that will run either onZero if the - /// given measurement result is Zero, or onOne otherwise. - /// - private static QVoid ExecuteConditionalStatement(Result measurementResult, ICallable onZero, ICallable onOne, OperationFunctor type, IQArray? ctrls) - { - if (measurementResult == Result.Zero) - { - RunClause(onZero, type, ctrls); - } - else - { - RunClause(onOne, type, ctrls); - } - return QVoid.Instance; - } - - /// - /// This is a wrapper for an if-statement that will run either onEqualOp if the - /// given measurement result are pairwise-equal to the given comparison results, - /// or onNonEqualOp otherwise. Pairwise-equality between the qubit arrays is - /// determined by the AreEqual static method. - /// - private static QVoid ExecuteConditionalStatement(IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp, OperationFunctor type, IQArray? ctrls) - { - if (AreEqual(measurementResults, comparisonResults)) - { - RunClause(onEqualOp, type, ctrls); - } - else - { - RunClause(onNonEqualOp, type, ctrls); - } - return QVoid.Instance; - } - - /// - /// Determines if the given measurement results are pairwise-equal with the given comparison results. - /// Pairwise-equality is where each element of the first array is equal to its corresponding element - /// in the second array. For example: - /// measurementResults[0] == comparisonResults[0] AND measurementResults[1] == comparisonResults[1] AND ... - /// All pairwise comparisons must result in equality for the two arrays to be pairwise-equal. - /// - /// If either array is null or their lengths are unequal, this defaults to returning 'true'. This - /// is done to be consistent with the logic found in QuantumProcessorBase.cs under the - /// StartConditionalStatement method. - /// - private static bool AreEqual(IQArray measurementResults, IQArray comparisonResults) - { - if (measurementResults == null || comparisonResults == null || measurementResults.Count != comparisonResults.Count) - { - // Defaulting to true is based on the QuantumProcessorBase.cs behavior, under StartConditionalStatement. - return true; - } - - for (int i = 0; i < measurementResults.Count; i++) - { - if (measurementResults[i] != comparisonResults[i]) - { - return false; - } - } - - return true; - } - - /// - /// If a controlled functor is being used with no controls, this will change it - /// to the appropriate non-controlled functor. Otherwise, the given functor is returned. - /// - private static OperationFunctor AdjustForNoControls(OperationFunctor type, IQArray? ctrls) - { - if (ctrls == null || ctrls.Count == 0) - { - type = type switch - { - OperationFunctor.Controlled => OperationFunctor.Body, - OperationFunctor.ControlledAdjoint => OperationFunctor.Adjoint, - _ => type, - }; - } - - return type; - } - - #endregion - - #region ApplyIfElse - - public class TracerApplyIfElse : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyIfElseIntrinsic - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyIfElse(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(Result, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - } - - public class TracerApplyIfElseA : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyIfElseIntrinsicA - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyIfElseA(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Adjoint, null); - }; - } - - public class TracerApplyIfElseC : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyIfElseIntrinsicC - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyIfElseC(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(Result, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - } - - public class TracerApplyIfElseCA : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyIfElseIntrinsicCA - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyIfElseCA(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(Result, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.ControlledAdjoint, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - } - - #endregion - - #region ApplyConditionally - - public class TracerApplyConditionally : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyConditionallyIntrinsic - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyConditionally(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(IQArray, IQArray, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - } - - public class TracerApplyConditionallyA : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyConditionallyIntrinsicA - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyConditionallyA(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - } - - public class TracerApplyConditionallyC : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyConditionallyIntrinsicC - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyConditionallyC(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(IQArray, IQArray, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - } - - public class TracerApplyConditionallyCA : Microsoft.Quantum.Simulation.QuantumProcessor.Extensions.ApplyConditionallyIntrinsicCA - { - private QCTraceSimulatorImpl tracerCore { get; } - - public TracerApplyConditionallyCA(QCTraceSimulatorImpl m) : base(m) - { - this.tracerCore = m; - } - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.ControlledAdjoint, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - } - - #endregion - } -} diff --git a/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs index 8b19da839c7..c9f8b4bb8e5 100644 --- a/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs +++ b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs @@ -8,293 +8,36 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor { public partial class QuantumProcessorDispatcher { - - private static void RunClause(ICallable op, OperationFunctor type, IQArray? ctrls) - { - switch (type) - { - case OperationFunctor.Body: op.Apply(QVoid.Instance); break; - case OperationFunctor.Adjoint: ((IAdjointable)(op)).Adjoint.Apply(QVoid.Instance); break; - case OperationFunctor.Controlled: ((IControllable)(op)).Controlled.Apply((ctrls, QVoid.Instance)); break; - case OperationFunctor.ControlledAdjoint: ((IUnitary)(op)).Controlled.Adjoint.Apply((ctrls, QVoid.Instance)); break; - } - } - - private static QVoid ExecuteConditionalStatementInternal(QuantumProcessorDispatcher Simulator, - long statement, - ICallable onEqualOp, - ICallable onNonEqualOp, - OperationFunctor type, - IQArray? ctrls) + public override void ExecuteBranchingBasedOnMeasurement(long condition, Action onEqual, Action onNonEqual) { - bool run; - - run = Simulator.QuantumProcessor.RunThenClause(statement); + bool run = this.QuantumProcessor.RunThenClause(condition); while (run) { - RunClause(onEqualOp, type, ctrls); - run = Simulator.QuantumProcessor.RepeatThenClause(statement); + onEqual?.Invoke(); + run = this.QuantumProcessor.RepeatThenClause(condition); } - run = Simulator.QuantumProcessor.RunElseClause(statement); + run = this.QuantumProcessor.RunElseClause(condition); while (run) { - RunClause(onNonEqualOp, type, ctrls); - run = Simulator.QuantumProcessor.RepeatElseClause(statement); + onNonEqual?.Invoke(); + run = this.QuantumProcessor.RepeatElseClause(condition); } - - Simulator.QuantumProcessor.EndConditionalStatement(statement); - - return QVoid.Instance; } - private static QVoid ExecuteConditionalStatement(QuantumProcessorDispatcher Simulator, - IQArray measurementResults, - IQArray resultsValues, - ICallable onEqualOp, - ICallable onNonEqualOp, - OperationFunctor type, - IQArray? ctrls) + public override long StartBranchingBasedOnMeasurement(Result result1, Result result2) { - long statement = Simulator.QuantumProcessor.StartConditionalStatement(measurementResults, resultsValues); - return ExecuteConditionalStatementInternal(Simulator, - statement, - onEqualOp, - onNonEqualOp, - type, - ctrls); + return this.QuantumProcessor.StartConditionalStatement(result1, result2); } - private static QVoid ExecuteConditionalStatement(QuantumProcessorDispatcher Simulator, - Result measurementResult, - Result resultValue, - ICallable onEqualOp, - ICallable onNonEqualOp, - OperationFunctor type, - IQArray? ctrls) + public override long StartBranchingBasedOnMeasurement(IQArray results1, IQArray results2) { - long statement = Simulator.QuantumProcessor.StartConditionalStatement(measurementResult, resultValue); - return ExecuteConditionalStatementInternal(Simulator, - statement, - onEqualOp, - onNonEqualOp, - type, - ctrls); - } - - - public class QuantumProcessorApplyIfElse : Extensions.ApplyIfElseIntrinsic - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyIfElse(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(Result, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - }; - } - - public class QuantumProcessorApplyIfElseA : Extensions.ApplyIfElseIntrinsicA - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyIfElseA(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); - }; + return this.QuantumProcessor.StartConditionalStatement(results1, results2); } - public class QuantumProcessorApplyIfElseC : Extensions.ApplyIfElseIntrinsicC + public override void EndBranchingBasedOnMeasurement(long statement) { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyIfElseC(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(Result, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Controlled, ctrls); - } - }; + this.QuantumProcessor.EndConditionalStatement(statement); } - - public class QuantumProcessorApplyIfElseCA : Extensions.ApplyIfElseIntrinsicCA - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyIfElseCA(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(Result, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Controlled, ctrls); - } - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.ControlledAdjoint, ctrls); - } - }; - } - - - - public class QuantumProcessorApplyConditionally : Extensions.ApplyConditionallyIntrinsic - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyConditionally(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(IQArray, IQArray, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - } - - public class QuantumProcessorApplyConditionallyA : Extensions.ApplyConditionallyIntrinsicA - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyConditionallyA(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - } - - public class QuantumProcessorApplyConditionallyC : Extensions.ApplyConditionallyIntrinsicC - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyConditionallyC(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(IQArray, IQArray, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Controlled, ctrls); - } - }; - } - - public class QuantumProcessorApplyConditionallyCA : Extensions.ApplyConditionallyIntrinsicCA - { - private QuantumProcessorDispatcher Simulator { get; } - - public QuantumProcessorApplyConditionallyCA(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Controlled, ctrls); - } - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - - if ((ctrls == null) || (ctrls.Count == 0)) - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - } - else - { - return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.ControlledAdjoint, ctrls); - } - }; - } - } } diff --git a/src/Simulation/Simulators/QuantumSimulator/ClassicalControl.cs b/src/Simulation/Simulators/QuantumSimulator/ClassicalControl.cs deleted file mode 100644 index c86e5abe4f0..00000000000 --- a/src/Simulation/Simulators/QuantumSimulator/ClassicalControl.cs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using Microsoft.Quantum.Simulation.Core; - -namespace Microsoft.Quantum.Simulation.Simulators -{ - public partial class QuantumSimulator - { - #region Static Methods - - /// - /// Runs the given functor of the given operation with the given control qubits. - /// - private static void RunClause(ICallable op, OperationFunctor type, IQArray? ctrls) - { - switch (type) - { - case OperationFunctor.Body: op.Apply(QVoid.Instance); break; - case OperationFunctor.Adjoint: ((IAdjointable)op).Adjoint.Apply(QVoid.Instance); break; - case OperationFunctor.Controlled: ((IControllable)op).Controlled.Apply((ctrls, QVoid.Instance)); break; - case OperationFunctor.ControlledAdjoint: ((IUnitary)op).Controlled.Adjoint.Apply((ctrls, QVoid.Instance)); break; - } - } - - /// - /// This is a wrapper for an if-statement that will run either onZero if the - /// given measurement result is Zero, or onOne otherwise. - /// - private static QVoid ExecuteConditionalStatement(Result measurementResult, ICallable onZero, ICallable onOne, OperationFunctor type, IQArray? ctrls) - { - if (measurementResult == Result.Zero) - { - RunClause(onZero, type, ctrls); - } - else - { - RunClause(onOne, type, ctrls); - } - return QVoid.Instance; - } - - /// - /// This is a wrapper for an if-statement that will run either onEqualOp if the - /// given measurement result are pairwise-equal to the given comparison results, - /// or onNonEqualOp otherwise. Pairwise-equality between the qubit arrays is - /// determined by the AreEqual static method. - /// - private static QVoid ExecuteConditionalStatement(IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp, OperationFunctor type, IQArray? ctrls) - { - if (AreEqual(measurementResults, comparisonResults)) - { - RunClause(onEqualOp, type, ctrls); - } - else - { - RunClause(onNonEqualOp, type, ctrls); - } - return QVoid.Instance; - } - - /// - /// Determines if the given measurement results are pairwise-equal with the given comparison results. - /// Pairwise-equality is where each element of the first array is equal to its corresponding element - /// in the second array. For example: - /// measurementResults[0] == comparisonResults[0] AND measurementResults[1] == comparisonResults[1] AND ... - /// All pairwise comparisons must result in equality for the two arrays to be pairwise-equal. - /// - /// If either array is null or their lengths are unequal, this defaults to returning 'true'. This - /// is done to be consistent with the logic found in QuantumProcessorBase.cs under the - /// StartConditionalStatement method. - /// - private static bool AreEqual(IQArray measurementResults, IQArray comparisonResults) - { - if (measurementResults == null || comparisonResults == null || measurementResults.Count != comparisonResults.Count) - { - // Defaulting to true is based on the QuantumProcessorBase.cs behavior, under StartConditionalStatement. - return true; - } - - for (int i = 0; i < measurementResults.Count; i++) - { - if (measurementResults[i] != comparisonResults[i]) - { - return false; - } - } - - return true; - } - - /// - /// If a controlled functor is being used with no controls, this will change it - /// to the appropriate non-controlled functor. Otherwise, the given functor is returned. - /// - private static OperationFunctor AdjustForNoControls(OperationFunctor type, IQArray? ctrls) - { - if (ctrls == null || ctrls.Count == 0) - { - type = type switch - { - OperationFunctor.Controlled => OperationFunctor.Body, - OperationFunctor.ControlledAdjoint => OperationFunctor.Adjoint, - _ => type, - }; - } - - return type; - } - - #endregion - - #region ApplyIfElse - - public class QSimApplyIfElse : QuantumProcessor.Extensions.ApplyIfElseIntrinsic - { - private QuantumSimulator Simulator { get; } - - public QSimApplyIfElse(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(Result, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - } - - public class QSimApplyIfElseA : QuantumProcessor.Extensions.ApplyIfElseIntrinsicA - { - private QuantumSimulator Simulator { get; } - - public QSimApplyIfElseA(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Adjoint, null); - }; - } - - public class QSimApplyIfElseC : QuantumProcessor.Extensions.ApplyIfElseIntrinsicC - { - private QuantumSimulator Simulator { get; } - - public QSimApplyIfElseC(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(Result, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - } - - public class QSimApplyIfElseCA : QuantumProcessor.Extensions.ApplyIfElseIntrinsicCA - { - private QuantumSimulator Simulator { get; } - - public QSimApplyIfElseCA(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(Result, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Body, null); - }; - - public override Func<(Result, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (Result measurementResult, ICallable onZero, ICallable onOne) = q; - return ExecuteConditionalStatement(measurementResult, onZero, onOne, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - - public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.ControlledAdjoint, ctrls); - return ExecuteConditionalStatement(measurementResult, onZero, onOne, type, ctrls); - }; - } - - #endregion - - #region ApplyConditionally - - public class QSimApplyConditionally : QuantumProcessor.Extensions.ApplyConditionallyIntrinsic - { - private QuantumSimulator Simulator { get; } - - public QSimApplyConditionally(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(IQArray, IQArray, ICallable, ICallable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - } - - public class QSimApplyConditionallyA : QuantumProcessor.Extensions.ApplyConditionallyIntrinsicA - { - private QuantumSimulator Simulator { get; } - - public QSimApplyConditionallyA(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - } - - public class QSimApplyConditionallyC : QuantumProcessor.Extensions.ApplyConditionallyIntrinsicC - { - private QuantumSimulator Simulator { get; } - - public QSimApplyConditionallyC(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(IQArray, IQArray, IControllable, IControllable), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - } - - public class QSimApplyConditionallyCA : QuantumProcessor.Extensions.ApplyConditionallyIntrinsicCA - { - private QuantumSimulator Simulator { get; } - - public QSimApplyConditionallyCA(QuantumSimulator m) : base(m) - { - this.Simulator = m; - } - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __Body__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); - }; - - public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => - { - (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp) = q; - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.Controlled, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - - public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => - { - (IQArray ctrls, (IQArray measurementResults, IQArray comparisonResults, ICallable onEqualOp, ICallable onNonEqualOp)) = q; - OperationFunctor type = AdjustForNoControls(OperationFunctor.ControlledAdjoint, ctrls); - return ExecuteConditionalStatement(measurementResults, comparisonResults, onEqualOp, onNonEqualOp, type, ctrls); - }; - } - - #endregion - } -} diff --git a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs index ffb9aef7f0c..bb7050d54e8 100644 --- a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs +++ b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.QuantumProcessor.Extensions; #nullable enable @@ -31,14 +32,11 @@ public abstract class SimulatorBase : AbstractFactory, IOperat public event Action? OnLog = null; public event Action>? OnException = null; - protected readonly int randomSeed; protected readonly Lazy randomGenerator; public int Seed => randomSeed; protected System.Random RandomGenerator => randomGenerator.Value; - - /// /// An event fired whenever a simulator has additional diagnostic data /// available for display (e.g. state information, assertion details, @@ -50,7 +48,6 @@ public abstract class SimulatorBase : AbstractFactory, IOperat public abstract string Name { get; } - /// /// If the execution finishes in failure, this method returns the call-stack of the Q# operations /// executed up to the point when the failure happened. @@ -82,7 +79,7 @@ public SimulatorBase(IQubitManager? qubitManager = null, int? seed = null) } } - public virtual I Get(Type T) + public I Get(Type T) { return (I)this.GetInstance(T); } @@ -97,7 +94,7 @@ public virtual I Get(Type T) /// If the operation has no body in the Q# file, and no override has been defined in the Simulator, /// this method will throw an InvalidOperationException. /// - public virtual I Get() where T : AbstractCallable, I + public I Get() where T : AbstractCallable, I { var key = typeof(T); return (I)this.GetInstance(key); @@ -271,8 +268,8 @@ public void CheckQubits(IQArray qubits, string arrayName) /// public class Allocate : Intrinsic.Allocate { - private SimulatorBase sim; - private IQubitManager? manager; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public Allocate(SimulatorBase m) : base(m) { @@ -282,26 +279,16 @@ public Allocate(SimulatorBase m) : base(m) public override Qubit Apply() { + Qubit qubit = manager.Allocate(); sim.OnAllocateQubits?.Invoke(1); - return manager.Allocate(); + return qubit; } public override IQArray Apply(long count) { - if (count < 0) - { - throw new InvalidOperationException($"Trying to allocate {count} qubits."); - } - else if (count == 0) - { - sim.OnAllocateQubits?.Invoke(count); - return new QArray(); - } - else - { - sim.OnAllocateQubits?.Invoke(count); - return manager.Allocate(count); - } + IQArray qubits = manager.Allocate(count); + sim.OnAllocateQubits?.Invoke(count); + return qubits; } } @@ -311,8 +298,8 @@ public override IQArray Apply(long count) /// public class Release : Intrinsic.Release { - private SimulatorBase sim; - private IQubitManager manager; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public Release(SimulatorBase m) : base(m) { @@ -339,22 +326,27 @@ public override void Apply(IQArray qubits) /// public class Borrow : Intrinsic.Borrow { - SimulatorBase sim; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public Borrow(SimulatorBase m) : base(m) { - sim = m; + this.sim = m; + this.manager = m.QubitManager; } public override Qubit Apply() { - return sim.QubitManager.Allocate(); + Qubit qubit = manager.Borrow(); + sim.OnBorrowQubits?.Invoke(1); + return qubit; } public override IQArray Apply(long count) { + IQArray qubits = manager.Borrow(count); sim.OnBorrowQubits?.Invoke(count); - return sim.QubitManager.Borrow(count); + return qubits; } } @@ -364,42 +356,26 @@ public override IQArray Apply(long count) /// public class Return : Intrinsic.Return { - SimulatorBase sim; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public Return(SimulatorBase m) : base(m) { - sim = m; + this.sim = m; + this.manager = m.QubitManager; } public override void Apply(Qubit q) { sim.OnReturnQubits?.Invoke(new QArray(new[] { q })); - sim.QubitManager.Return(q); + manager.Return(q); } public override void Apply(IQArray qubits) { sim.OnReturnQubits?.Invoke(qubits); - sim.QubitManager.Return(qubits); - } - } - - /// - /// Implements the Log statement as an operation. It just calls Console.WriteLine. - /// - public class Message : Intrinsic.Message - { - private SimulatorBase sim; - public Message(SimulatorBase m) : base(m) - { - sim = m; + manager.Return(qubits); } - - public override Func __Body__ => (msg) => - { - sim.OnLog?.Invoke(msg); - return QVoid.Instance; - }; } /// @@ -407,14 +383,17 @@ public Message(SimulatorBase m) : base(m) /// public class GetQubitsAvailableToUse : Environment.GetQubitsAvailableToUse { - private SimulatorBase sim; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public GetQubitsAvailableToUse(SimulatorBase m) : base(m) { - sim = m; + this.sim = m; + this.manager = m.QubitManager; } - public override Func __Body__ => (arg) => sim.QubitManager.GetFreeQubitsCount(); + public override Func __Body__ => (arg) => + manager.GetFreeQubitsCount(); } /// @@ -422,15 +401,34 @@ public GetQubitsAvailableToUse(SimulatorBase m) : base(m) /// public class GetQubitsAvailableToBorrow : Environment.GetQubitsAvailableToBorrow { - private SimulatorBase sim; + protected readonly SimulatorBase sim; + protected readonly IQubitManager manager; public GetQubitsAvailableToBorrow(SimulatorBase m) : base(m) { - sim = m; + this.sim = m; + this.manager = m.QubitManager; } - public override Func __Body__ => (arg) => sim.QubitManager.GetParentQubitsAvailableToBorrowCount() + - sim.QubitManager.GetFreeQubitsCount(); + public override Func __Body__ => (arg) => + manager.GetParentQubitsAvailableToBorrowCount() + manager.GetFreeQubitsCount(); + } + + + /// + /// Implements the Log statement as an operation. It just calls Console.WriteLine. + /// + public class Message : Intrinsic.Message + { + protected readonly SimulatorBase sim; + public Message(SimulatorBase m) : base(m) => + sim = m; + + public override Func __Body__ => (msg) => + { + sim.OnLog?.Invoke(msg); + return QVoid.Instance; + }; } /// @@ -439,12 +437,9 @@ public GetQubitsAvailableToBorrow(SimulatorBase m) : base(m) /// public class DrawRandomInt : Random.DrawRandomInt { - private SimulatorBase sim; - - public DrawRandomInt(SimulatorBase m) : base(m) - { + protected readonly SimulatorBase sim; + public DrawRandomInt(SimulatorBase m) : base(m) => sim = m; - } public override Func<(long, long), long> __Body__ => arg => { @@ -463,12 +458,9 @@ public DrawRandomInt(SimulatorBase m) : base(m) /// public class DrawRandomDouble : Random.DrawRandomDouble { - private SimulatorBase sim; - - public DrawRandomDouble(SimulatorBase m) : base(m) - { + protected readonly SimulatorBase sim; + public DrawRandomDouble(SimulatorBase m) : base(m) => sim = m; - } public override Func<(double, double), double> __Body__ => arg => { @@ -482,6 +474,256 @@ public DrawRandomDouble(SimulatorBase m) : base(m) }; } + #region Branching based on measurement + + public class ApplyIfElse : ApplyIfElseIntrinsic + { + protected readonly SimulatorBase sim; + public ApplyIfElse(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(Result, ICallable, ICallable), QVoid> __Body__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + return QVoid.Instance; + }; + } + + public class ApplyIfElseA : ApplyIfElseIntrinsicA + { + protected readonly SimulatorBase sim; + public ApplyIfElseA(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(Result, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(Result, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); + return QVoid.Instance; + }; + } + + public class ApplyIfElseC : ApplyIfElseIntrinsicC + { + protected readonly SimulatorBase sim; + public ApplyIfElseC(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(Result, IControllable, IControllable), QVoid> __Body__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => + { + (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Body, null) : (OperationFunctor.Controlled, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, specKind, controls); + return QVoid.Instance; + }; + } + + public class ApplyIfElseCA : ApplyIfElseIntrinsicCA + { + protected readonly SimulatorBase sim; + public ApplyIfElseCA(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(Result, IUnitary, IUnitary), QVoid> __Body__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(Result, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => + { + (Result measurementResult, ICallable onZero, ICallable onOne) = q; + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => + { + (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Body, null) : (OperationFunctor.Controlled, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, specKind, controls); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => + { + (IQArray ctrls, (Result measurementResult, ICallable onZero, ICallable onOne)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Adjoint, null) : (OperationFunctor.ControlledAdjoint, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResult, Result.Zero, onZero, onOne, specKind, controls); + return QVoid.Instance; + }; + } + + public class ApplyConditionally : ApplyConditionallyIntrinsic + { + protected readonly SimulatorBase sim; + public ApplyConditionally(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(IQArray, IQArray, ICallable, ICallable), QVoid> __Body__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + return QVoid.Instance; + }; + } + + public class ApplyConditionallyA : ApplyConditionallyIntrinsicA + { + protected readonly SimulatorBase sim; + public ApplyConditionallyA(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __Body__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> __AdjointBody__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); + return QVoid.Instance; + }; + } + + public class ApplyConditionallyC : ApplyConditionallyIntrinsicC + { + protected readonly SimulatorBase sim; + public ApplyConditionallyC(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(IQArray, IQArray, IControllable, IControllable), QVoid> __Body__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> __ControlledBody__ => (q) => + { + (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Body, null) : (OperationFunctor.Controlled, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, specKind, controls); + return QVoid.Instance; + }; + } + + public class ApplyConditionallyCA : ApplyConditionallyIntrinsicCA + { + protected readonly SimulatorBase sim; + public ApplyConditionallyCA(SimulatorBase m) : base(m) => + sim = m; + + public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __Body__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> __AdjointBody__ => (q) => + { + (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp) = q; + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledBody__ => (q) => + { + (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Body, null) : (OperationFunctor.Controlled, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, specKind, controls); + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> __ControlledAdjointBody__ => (q) => + { + (IQArray ctrls, (IQArray measurementResults, IQArray resultsValues, ICallable onEqualOp, ICallable onNonEqualOp)) = q; + (var specKind, IQArray? controls) = ctrls?.Count == 0 ? (OperationFunctor.Adjoint, null) : (OperationFunctor.ControlledAdjoint, ctrls); + this.sim.BranchingBasedOnMeasurement(measurementResults, resultsValues, onEqualOp, onNonEqualOp, specKind, controls); + return QVoid.Instance; + }; + } + + private Action BuildClause(ICallable op, OperationFunctor type, IQArray? ctrls) => + type switch + { + OperationFunctor.Body => () => op.Apply(QVoid.Instance), + OperationFunctor.Adjoint => () => ((IAdjointable)op).Adjoint.Apply(QVoid.Instance), + OperationFunctor.Controlled => () => ((IControllable)op).Controlled.Apply((ctrls, QVoid.Instance)), + OperationFunctor.ControlledAdjoint => () => ((IUnitary)op).Controlled.Adjoint.Apply((ctrls, QVoid.Instance)), + _ => throw new NotImplementedException("unknown specialization"), + }; + + private void BranchingBasedOnMeasurement(IQArray results1, IQArray results2, ICallable onEqual, ICallable onNonEqual, OperationFunctor type, IQArray? ctrls) + { + long statement = this.StartBranchingBasedOnMeasurement(results1, results2); + ExecuteBranchingBasedOnMeasurement(statement, BuildClause(onEqual, type, ctrls), BuildClause(onNonEqual, type, ctrls)); + this.EndBranchingBasedOnMeasurement(statement); + } + + private void BranchingBasedOnMeasurement(Result result1, Result result2, ICallable onEqual, ICallable onNonEqual, OperationFunctor type, IQArray? ctrls) + { + long statement = this.StartBranchingBasedOnMeasurement(result1, result2); + ExecuteBranchingBasedOnMeasurement(statement, BuildClause(onEqual, type, ctrls), BuildClause(onNonEqual, type, ctrls)); + this.EndBranchingBasedOnMeasurement(statement); + } + + public virtual void ExecuteBranchingBasedOnMeasurement(long condition, Action onEqual, Action onNonEqual) + { + switch (condition) + { + case 1: onEqual?.Invoke(); break; + case 0: onNonEqual?.Invoke(); break; + default: throw new NotImplementedException("value for condition was expected to be either 0 (when the condition is false) or 1 (when the condition is true)"); + } + } + + /// + /// By default, 1 indicates that all results are equal, i.e. the statement is to enter the then-clause, + /// and 0 indicates that they are not, i.e. the statement is to enter then else-clause. + /// If both arrays are null, then 1 is returned. + /// + public virtual long StartBranchingBasedOnMeasurement(IQArray results1, IQArray results2) + { + if (results1 == null) { return results2 == null ? 1 : 0; }; + if (results1.Count != results2?.Count) { return 0; }; + return results1.Zip(results2, (r1, r2) => (r1, r2)).Any(pair => pair.r1 != pair.r2) ? 0 : 1; + } + + /// + /// By default, 1 indicates that both results are equal, i.e. the statement is to enter the then-clause. + /// and 0 indicates that they are not, i.e. the statement is to enter then else-clause. + /// + public virtual long StartBranchingBasedOnMeasurement(Result result1, Result result2) + { + return result1 == result2 ? 1 : 0; + } + + public virtual void EndBranchingBasedOnMeasurement(long statement) + { } + + #endregion + public virtual void StartOperation(ICallable operation, IApplyData inputValue) { OnOperationStart?.Invoke(operation, inputValue); @@ -492,7 +734,7 @@ public virtual void EndOperation(ICallable operation, IApplyData resultValue) OnOperationEnd?.Invoke(operation, resultValue); } - public virtual void Fail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo ) + public virtual void Fail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionInfo) { OnFail?.Invoke(exceptionInfo); }