From 22a8e21423f73bef98f7c4f092995090668b73b0 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 25 Feb 2021 13:07:36 -0800 Subject: [PATCH 1/3] Make non-intrinsic ClassicalControl callables internal --- .../QSharpCore/Properties/AssemblyInfo.cs | 9 - .../QSharpFoundation/ClassicalControl.qs | 75 ++++---- .../QuantumSimulator/SimulatorBase.cs | 164 +----------------- 3 files changed, 37 insertions(+), 211 deletions(-) delete mode 100644 src/Simulation/QSharpCore/Properties/AssemblyInfo.cs diff --git a/src/Simulation/QSharpCore/Properties/AssemblyInfo.cs b/src/Simulation/QSharpCore/Properties/AssemblyInfo.cs deleted file mode 100644 index 109c9a91f80..00000000000 --- a/src/Simulation/QSharpCore/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// Allow the simulator assembly to use our internal methods -[assembly: InternalsVisibleTo("Microsoft.Quantum.Simulators" + SigningConstants.PUBLIC_KEY)] \ No newline at end of file diff --git a/src/Simulation/QSharpFoundation/ClassicalControl.qs b/src/Simulation/QSharpFoundation/ClassicalControl.qs index 38d486e8e70..017277ce07a 100644 --- a/src/Simulation/QSharpFoundation/ClassicalControl.qs +++ b/src/Simulation/QSharpFoundation/ClassicalControl.qs @@ -3,32 +3,31 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: update namespace to a more appropriate name { - operation NoOp() : Unit is Ctl + Adj {} + open Microsoft.Quantum.Canon; // Private helper operations. - operation Delay<'T>(op : ('T => Unit), arg : 'T, aux : Unit) : Unit { + internal 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 { + internal 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 { + internal 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 { + internal operation DelayCA<'T>(op : ('T => Unit is Ctl + Adj), arg : 'T, aux : Unit) : Unit is Ctl + Adj { op(arg); } - // Private helper operations. 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 is Adj { + internal operation ApplyIfElseIntrinsicA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Adj) , onResultOneOp : (Unit => Unit is Adj)) : Unit is Adj { body (...) { ApplyIfElseIntrinsic(measurementResult, onResultZeroOp, onResultOneOp); } @@ -37,7 +36,7 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat } } - operation ApplyIfElseIntrinsicC(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl)) : Unit is Ctl { + internal operation ApplyIfElseIntrinsicC(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl)) : Unit is Ctl { body (...) { ApplyIfElseIntrinsic(measurementResult, onResultZeroOp, onResultOneOp); } @@ -46,7 +45,7 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat } } - operation ApplyIfElseIntrinsicCA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { + internal operation ApplyIfElseIntrinsicCA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { body (...) { ApplyIfElseIntrinsic(measurementResult, onResultZeroOp, onResultOneOp); } @@ -67,7 +66,7 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat body intrinsic; } - operation ApplyConditionallyIntrinsicA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Adj) , onNonEqualOp : (Unit => Unit is Adj)) : Unit is Adj { + internal operation ApplyConditionallyIntrinsicA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Adj) , onNonEqualOp : (Unit => Unit is Adj)) : Unit is Adj { body (...) { ApplyConditionallyIntrinsic(measurementResults, resultsValues, onEqualOp, onNonEqualOp); } @@ -76,7 +75,7 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat } } - operation ApplyConditionallyIntrinsicC(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl) , onNonEqualOp : (Unit => Unit is Ctl)) : Unit is Ctl { + internal operation ApplyConditionallyIntrinsicC(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl) , onNonEqualOp : (Unit => Unit is Ctl)) : Unit is Ctl { body (...) { ApplyConditionallyIntrinsic(measurementResults, resultsValues, onEqualOp, onNonEqualOp); } @@ -85,7 +84,7 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat } } - operation ApplyConditionallyIntrinsicCA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl + Adj) , onNonEqualOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { + internal operation ApplyConditionallyIntrinsicCA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl + Adj) , onNonEqualOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { body (...) { ApplyConditionallyIntrinsic(measurementResults, resultsValues, onEqualOp, onNonEqualOp); } @@ -100,113 +99,109 @@ namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions //ToDo: updat } } - // Public operations that match Canon names. // This corresponds to "if" statement of the following form in Q#: // if (measurementResult == Zero) {onResultZeroOp(zeroArg);} else {onResultOneOp(oneArg);} - operation ApplyIfElseR<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T) , (onResultOneOp : ('U => Unit), oneArg : 'U)) : Unit { + internal 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 { + internal 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 { + internal 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 ApplyIfElseRCA<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj + Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj + Ctl), oneArg : 'U)) : Unit is Ctl + Adj { + internal operation ApplyIfElseRCA<'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); } - // Public operations that match Canon names. // This corresponds to "if" statement of the following form in Q#: // if (measurementResult == Zero) {onResultZeroOp(zeroArg);} - operation ApplyIfZero<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T)) : Unit { + internal operation ApplyIfZero<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit), zeroArg : 'T)) : Unit { let zeroOp = Delay(onResultZeroOp, zeroArg, _); - let oneOp = Delay(NoOp, (), _); + let oneOp = Delay(NoOp, (), _); ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); } - operation ApplyIfZeroA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T)) : Unit is Adj{ + internal operation ApplyIfZeroA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T)) : Unit is Adj{ let zeroOp = DelayA(onResultZeroOp, zeroArg, _); - let oneOp = DelayA(NoOp, (), _); + let oneOp = DelayA(NoOp, (), _); ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); } - operation ApplyIfZeroC<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T)) : Unit is Ctl { + internal operation ApplyIfZeroC<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T)) : Unit is Ctl { let zeroOp = DelayC(onResultZeroOp, zeroArg, _); - let oneOp = DelayC(NoOp, (), _); + 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 { + internal 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, (), _); + let oneOp = DelayCA(NoOp, (), _); ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); } - // Public operations that match Canon names. // This corresponds to "if" statement of the following form in Q#: // if (measurementResult == One) {onResultOneOp(oneArg);} - operation ApplyIfOne<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit), oneArg : 'T)) : Unit { + internal operation ApplyIfOne<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit), oneArg : 'T)) : Unit { let oneOp = Delay(onResultOneOp, oneArg, _); - let zeroOp = Delay(NoOp, (), _); + let zeroOp = Delay(NoOp, (), _); ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); } - operation ApplyIfOneA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T)) : Unit is Adj { + internal operation ApplyIfOneA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T)) : Unit is Adj { let oneOp = DelayA(onResultOneOp, oneArg, _); - let zeroOp = DelayA(NoOp, (), _); + let zeroOp = DelayA(NoOp, (), _); ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); } - operation ApplyIfOneC<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T)) : Unit is Ctl { + internal operation ApplyIfOneC<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T)) : Unit is Ctl { let oneOp = DelayC(onResultOneOp, oneArg, _); - let zeroOp = DelayC(NoOp, (), _); + 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 { + internal 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, (), _); + let zeroOp = DelayCA(NoOp, (), _); ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); } - // Public operations that match Canon names. // This corresponds to "if" statement of the following form in Q#: // if ((measurementResults[0] == resultsValues[0]) && (measurementResults[1] == resultsValues[1])) {onEqualOp(equalArg);} else {onNonEqualOp(nonEqualArg);} - operation ApplyConditionally<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit), equalArg : 'T) , (onNonEqualOp : ('U => Unit), nonEqualArg : 'U)) : Unit { + internal 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 { + internal 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 { + internal 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 { + internal 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/QuantumSimulator/SimulatorBase.cs b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs index 0d5d5b53824..21e69060336 100644 --- a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs +++ b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs @@ -491,7 +491,7 @@ public DrawRandomDouble(SimulatorBase m) : base(m) => #region Branching based on measurement - public class ApplyIfElse : ApplyIfElseIntrinsic + class ApplyIfElse : ApplyIfElseIntrinsic { protected readonly SimulatorBase sim; public ApplyIfElse(SimulatorBase m) : base(m) => @@ -505,87 +505,7 @@ public ApplyIfElse(SimulatorBase m) : base(m) => }; } - 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 + class ApplyConditionally : ApplyConditionallyIntrinsic { protected readonly SimulatorBase sim; public ApplyConditionally(SimulatorBase m) : base(m) => @@ -599,86 +519,6 @@ public ApplyConditionally(SimulatorBase m) : base(m) => }; } - 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 { From b9a706aed18aeb83541a67f98683a43aa8bf6e10 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 25 Feb 2021 13:11:44 -0800 Subject: [PATCH 2/3] Put back accidentally removed "public" --- src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs index 21e69060336..eb8b27f1ee6 100644 --- a/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs +++ b/src/Simulation/Simulators/QuantumSimulator/SimulatorBase.cs @@ -491,7 +491,7 @@ public DrawRandomDouble(SimulatorBase m) : base(m) => #region Branching based on measurement - class ApplyIfElse : ApplyIfElseIntrinsic + public class ApplyIfElse : ApplyIfElseIntrinsic { protected readonly SimulatorBase sim; public ApplyIfElse(SimulatorBase m) : base(m) => @@ -505,7 +505,7 @@ public ApplyIfElse(SimulatorBase m) : base(m) => }; } - class ApplyConditionally : ApplyConditionallyIntrinsic + public class ApplyConditionally : ApplyConditionallyIntrinsic { protected readonly SimulatorBase sim; public ApplyConditionally(SimulatorBase m) : base(m) => From 8d669afbea67e3a3b846ddcfe128243950928769 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 26 Feb 2021 00:29:28 -0800 Subject: [PATCH 3/3] Moving QIR conditional tests to targeted project --- .gitignore | 1 + src/QirRuntime/build-qir-runtime.ps1 | 10 ++ src/QirRuntime/test/QIR-static/CMakeLists.txt | 1 + .../test/QIR-static/qir-test-conditionals.cpp | 4 +- .../QIR-static/qsharp-targeted/entrypoint.qs | 10 ++ .../test/QIR-static/qsharp-targeted/main.cs | 13 ++ .../qsharp-targeted/qir-targeted.csproj | 17 +++ .../qir-test-conditionals.qs | 131 +++++++++--------- .../test/QIR-static/qsharp/qir-test-arrays.qs | 5 - 9 files changed, 123 insertions(+), 69 deletions(-) create mode 100644 src/QirRuntime/test/QIR-static/qsharp-targeted/entrypoint.qs create mode 100644 src/QirRuntime/test/QIR-static/qsharp-targeted/main.cs create mode 100644 src/QirRuntime/test/QIR-static/qsharp-targeted/qir-targeted.csproj rename src/QirRuntime/test/QIR-static/{qsharp => qsharp-targeted}/qir-test-conditionals.qs (77%) diff --git a/.gitignore b/.gitignore index f77b7e72b01..a1235dd9a76 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ bld/ [Ll]og/ [Dd]rops/ **/qir-gen.ll +**/qir-targeted.ll # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/src/QirRuntime/build-qir-runtime.ps1 b/src/QirRuntime/build-qir-runtime.ps1 index 63247ebaab7..803fad06871 100644 --- a/src/QirRuntime/build-qir-runtime.ps1 +++ b/src/QirRuntime/build-qir-runtime.ps1 @@ -12,6 +12,16 @@ if ($Env:ENABLE_QIRRUNTIME -eq "true") { Copy-Item -Path (Join-Path $qirStaticPath qir *.ll) -Destination (Split-Path $qirStaticPath -Parent) # Also copy to drops so it ends up in build artifacts, for easier post-build debugging. Copy-Item -Path (Join-Path $qirStaticPath qir *.ll) -Destination $Env:DROPS_DIR + + $qirTargetedPath = Join-Path $PSScriptRoot test QIR-static qsharp-targeted + dotnet build $qirTargetedPath -c $Env:BUILD_CONFIGURATION -v $Env:BUILD_VERBOSITY + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to compile Q# project at '$qirTargetedPath' into QIR." + return + } + Copy-Item -Path (Join-Path $qirTargetedPath qir *.ll) -Destination (Split-Path $qirTargetedPath -Parent) + # Also copy to drops so it ends up in build artifacts, for easier post-build debugging. + Copy-Item -Path (Join-Path $qirTargetedPath qir *.ll) -Destination $Env:DROPS_DIR Write-Host "##[info]Build QIR Runtime" $oldCC = $env:CC diff --git a/src/QirRuntime/test/QIR-static/CMakeLists.txt b/src/QirRuntime/test/QIR-static/CMakeLists.txt index f82e0b7a928..4d592e4e784 100644 --- a/src/QirRuntime/test/QIR-static/CMakeLists.txt +++ b/src/QirRuntime/test/QIR-static/CMakeLists.txt @@ -3,6 +3,7 @@ set(TEST_FILES qir-test-noqsharp qir-gen + qir-targeted ) foreach(file ${TEST_FILES}) diff --git a/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp b/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp index 556f63d12d6..109fa07f678 100644 --- a/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp +++ b/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp @@ -154,7 +154,7 @@ TEST_CASE("QIR: ApplyConditionally", "[qir][qir.conditionals]") CHECK_NOTHROW(Microsoft__Quantum__Testing__QIR__TestApplyConditionally__body()); INFO(qapi->GetHistory()); - CHECK(qapi->xCallbacks.size() == 4); - CHECK(qapi->cxCallbacks.size() == 2); + CHECK(qapi->xCallbacks.size() == 2); + CHECK(qapi->cxCallbacks.size() == 0); CHECK(qapi->otherCallbacks.size() == 0); } diff --git a/src/QirRuntime/test/QIR-static/qsharp-targeted/entrypoint.qs b/src/QirRuntime/test/QIR-static/qsharp-targeted/entrypoint.qs new file mode 100644 index 00000000000..7740b476533 --- /dev/null +++ b/src/QirRuntime/test/QIR-static/qsharp-targeted/entrypoint.qs @@ -0,0 +1,10 @@ +namespace Microsoft.Quantum.Testing.QIR { + + @EntryPoint() + operation Tests() : Unit { + TestApplyIf(); + TestApplyIfWithFunctors(); + TestApplyConditionally(); + } + +} diff --git a/src/QirRuntime/test/QIR-static/qsharp-targeted/main.cs b/src/QirRuntime/test/QIR-static/qsharp-targeted/main.cs new file mode 100644 index 00000000000..3e0cec7acae --- /dev/null +++ b/src/QirRuntime/test/QIR-static/qsharp-targeted/main.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Currently, compiling to QIR has to suppress C# generation but then we need to provide Main function ourselves. +namespace CompilerWorkaround +{ + class Program + { + static void Main(string[] args) + { + } + } +} \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-static/qsharp-targeted/qir-targeted.csproj b/src/QirRuntime/test/QIR-static/qsharp-targeted/qir-targeted.csproj new file mode 100644 index 00000000000..4b0af429edc --- /dev/null +++ b/src/QirRuntime/test/QIR-static/qsharp-targeted/qir-targeted.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.1 + false + True + false + false + honeywell + + + + + + + diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs b/src/QirRuntime/test/QIR-static/qsharp-targeted/qir-test-conditionals.qs similarity index 77% rename from src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs rename to src/QirRuntime/test/QIR-static/qsharp-targeted/qir-test-conditionals.qs index 28a1b755a64..202bf1aac10 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-conditionals.qs +++ b/src/QirRuntime/test/QIR-static/qsharp-targeted/qir-test-conditionals.qs @@ -1,63 +1,70 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -namespace Microsoft.Quantum.Testing.QIR { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Simulation.QuantumProcessor.Extensions; - - operation TestApplyIf() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); // expected: r1 = Zero - X(q2); - let r2 = M(q2); // expected: r2 = One - - ApplyIfElseR(r1, (X, q1), (Y, q1)); - ApplyIfElseR(r2, (Y, q1), (X, q1)); - - // Other variants - ApplyIfElseRA(r1, (X, q1), (Y, q1)); - ApplyIfElseRC(r1, (X, q1), (Y, q1)); - ApplyIfElseRCA(r1, (X, q1), (Y, q1)); - ApplyIfOne(r2, (X, q1)); - ApplyIfZero(r1, (X, q1)); - } - - operation TestApplyIfWithFunctors() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); - X(q2); - let r2 = M(q2); - - Adjoint ApplyIfElseRCA(r1, (X, q1), (Y, q1)); - Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); - Adjoint Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); - Adjoint ApplyIfElseRA(r1, (X, q1), (Y, q1)); - Controlled ApplyIfElseRC([q2], (r1, (X, q1), (Y, q1))); - Adjoint ApplyIfOneA(r2, (X, q1)); - Controlled ApplyIfOneC([q2], (r2, (X, q1))); - Adjoint Controlled ApplyIfOneCA([q2], (r2, (X, q1))); - Adjoint ApplyIfZeroA(r1, (X, q1)); - Controlled ApplyIfZeroC([q2], (r1, (X, q1))); - Adjoint Controlled ApplyIfZeroCA([q2], (r1, (X, q1))); - } - - operation TestApplyConditionally() : Unit { - use q1 = Qubit(); - use q2 = Qubit(); - - let r1 = M(q1); - X(q2); - let r2 = M(q2); - - ApplyConditionally([r1], [r2], (Y, q1), (X, q1)); - ApplyConditionally([r1, One], [Zero, r2], (X, q1), (Y, q1)); - - Adjoint ApplyConditionallyA([r1], [r2], (Y, q1), (X, q1)); - Controlled ApplyConditionallyC([q2], ([r1], [r2], (Y, q1), (X, q1))); - Adjoint Controlled ApplyConditionallyCA([q2], ([r1], [r2], (Y, q1), (X, q1))); - } - +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Testing.QIR { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + + operation TestApplyIf() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); // expected: r1 = Zero + X(q2); + let r2 = M(q2); // expected: r2 = One + + ApplyIfElseR(r1, (X, q1), (Y, q1)); + ApplyIfElseR(r2, (Y, q1), (X, q1)); + + // Other variants + ApplyIfElseRA(r1, (X, q1), (Y, q1)); + ApplyIfElseRC(r1, (X, q1), (Y, q1)); + ApplyIfElseRCA(r1, (X, q1), (Y, q1)); + ApplyIfOne(r2, (X, q1)); + ApplyIfZero(r1, (X, q1)); + } + + operation TestApplyIfWithFunctors() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); + X(q2); + let r2 = M(q2); + + Adjoint ApplyIfElseRCA(r1, (X, q1), (Y, q1)); + Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); + Adjoint Controlled ApplyIfElseRCA([q2], (r1, (X, q1), (Y, q1))); + Adjoint ApplyIfElseRA(r1, (X, q1), (Y, q1)); + Controlled ApplyIfElseRC([q2], (r1, (X, q1), (Y, q1))); + Adjoint ApplyIfOneA(r2, (X, q1)); + Controlled ApplyIfOneC([q2], (r2, (X, q1))); + Adjoint Controlled ApplyIfOneCA([q2], (r2, (X, q1))); + Adjoint ApplyIfZeroA(r1, (X, q1)); + Controlled ApplyIfZeroC([q2], (r1, (X, q1))); + Adjoint Controlled ApplyIfZeroCA([q2], (r1, (X, q1))); + } + + operation TestApplyConditionally() : Unit { + use q1 = Qubit(); + use q2 = Qubit(); + + let r1 = M(q1); + X(q2); + let r2 = M(q2); + + if r1 == r2 { + Y(q1); + } + else { + X(q1); + } + + if r1 == Zero and One == r2 { + X(q1); + } + else { + Y(q1); + } + } + } \ No newline at end of file diff --git a/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs b/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs index 195e9905ec1..a60a658a273 100644 --- a/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs +++ b/src/QirRuntime/test/QIR-static/qsharp/qir-test-arrays.qs @@ -56,11 +56,6 @@ namespace Microsoft.Quantum.Testing.QIR { let res18 = ArcTanTest(); let res19 = ParityTest(); MessageTest("Test"); - - // Conditionals: - TestApplyIf(); - TestApplyIfWithFunctors(); - TestApplyConditionally(); } return sum; }