diff --git a/src/Simulation/Common/IQuantumProcessor.cs b/src/Simulation/Common/IQuantumProcessor.cs new file mode 100644 index 00000000000..565b44d0356 --- /dev/null +++ b/src/Simulation/Common/IQuantumProcessor.cs @@ -0,0 +1,640 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.Common +{ + /// + /// An interface for implementing QDK target quantum machines that work on a quantum circuit level. + /// + /// + /// To implement a target machine that executes quantum commands, implement this interface. + /// Consider using as a stub for easy impementation of this interface. + /// Implementors of interface do not manage qubits on their own. + /// All qubit management (allocation, dealocation, etc.) is done by the caller of this interface. + /// Implementors are notified when qubits are allocated, released, borrowed and returned allowing them to react to these events if necessary. + /// + public interface IQuantumProcessor + { + /// + /// Called when Microsoft.Quantum.Intrinsic.X is called in Q#. + /// When this is invoked, it is expected that the X gate gets applied to the given . The gate is given by matrix X=((0,1),(1,0)). + /// + /// + /// When adjoint of X is called in Q#, this same method is called because X is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void X(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.X is called in Q#. + /// When this is invoked, it is expected that the X gate gets applied to the given controlled on . The gate is given by matrix X=((0,1),(1,0)). + /// + /// + /// When adjoint of Controlled X is called in Q#, this same method is called because X is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledX(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// When this is invoked, it is expected that the Y gate gets applied to the given . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// + /// + /// When adjoint of Y is called in Q#, this same method is called because Y is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Y(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.Y is called in Q#. + /// When this is invoked, it is expected that the Y gate gets applied to the given controlled on . The gate is given by matrix Y=((0,-𝑖),(𝑖,0)). + /// + /// + /// When adjoint of Controlled Y is called in Q#, this same method is called because Y is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledY(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// When this is invoked, it is expected that the Z gate gets applied to the given . The gate is given by matrix Z=((1,0),(0,-1)). + /// + /// + /// When adjoint of Z is called in Q#, this same method is called because Z is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Z(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.Z is called in Q#. + /// When this is invoked, it is expected that the Z gate gets applied to the given controlled on . The gate is given by matrix Z=((1,0),(0,-1)). + /// + /// + /// When adjoint of Controlled Z is called in Q#, this same method is called because Z is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledZ(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// When this is invoked, it is expected that the gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states gets applied. + /// + /// + /// When adjoint of SWAP is called in Q#, this same method is called because SWAP is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// First qubit to be swapped. + /// Second qubit to be swapped. + void SWAP(Qubit qubit1, Qubit qubit2); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.SWAP is called in Q#. + /// When this is invoked, it is expected that the gate given by rule |ψ⟩⊗|ϕ⟩ ↦ |ϕ⟩⊗|ψ⟩ where |ϕ⟩,|ψ⟩ arbitrary one qubit states gets applied, controlled on . + /// + /// + /// When adjoint of Controlled SWAP is called in Q#, this same method is called because SWAP is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// First qubit to be swapped. + /// Second qubit to be swapped. + void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2); + + /// + /// Called when Microsoft.Quantum.Intrinsic.H is called in Q#. + /// When this is invoked, it is expected that the Hadamard gate gets applied to . The gate is given by matrix H=((1,1),(1,-1))/√2. + /// + /// + /// When adjoint of H is called in Q#, this same method is called because Hadamard is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void H(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.H is called in Q#. + /// When this is invoked, it is expected that the Hadamard gate gets applied to controlled on . The gate is given by matrix H=((1,1),(1,-1))/√2. + /// + /// + /// When adjoint of Controlled H is called in Q#, this same method is called because Hadamard is self-adjoint. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledH(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.S is called in Q#. + /// When this is invoked, it is expected that the S gate gets applied to . The gate is given by matrix S=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void S(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.S is called in Q#. + /// When this is invoked, it is expected that the S gate gets applied to controlled on . The gate is given by matrix S=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of Controlled S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledS(IQArray controls, Qubit qubit); + + /// + /// Called when adjoint Microsoft.Quantum.Intrinsic.S is called in Q#. + /// When this is invoked, it is expected that the S† gate gets applied to . The gate is given by matrix S†=((1,0),(0,-𝑖)). + /// + /// + /// When adjoint of Adjoint S is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void SAdjoint(Qubit qubit); + + /// + /// Called when controlled adjoint Microsoft.Quantum.Intrinsic.S is called in Q#. + /// When this is invoked, it is expected that the S† gate gets applied to controlled on . The gate is given by matrix S†=((1,0),(0,𝑖)). + /// + /// + /// When adjoint of Controlled S† is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledSAdjoint(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.T is called in Q#. + /// When this is invoked, it is expected that the T gate gets applied to . The gate is given by matrix T=((1,0),(0,𝑒𝑥𝑝(𝑖⋅π/4))). + /// + /// + /// When adjoint of T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void T(Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.T is called in Q#. + /// When this is invoked, it is expected that the T gate gets applied to controlled on . The gate is given by matrix T=((1,0),(0,𝑒𝑥𝑝(𝑖⋅π/4))). + /// + /// + /// When adjoint of Controlled T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledT(IQArray controls, Qubit qubit); + + /// + /// Called when adjoint Microsoft.Quantum.Intrinsic.T is called in Q#. + /// When this is invoked, it is expected that the T† gate gets applied to . The gate is given by matrix T†=((1,0),(0,𝑒𝑥𝑝(-𝑖⋅π/4))). + /// + /// + /// When adjoint of Adjoint T is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void TAdjoint(Qubit qubit); + + /// + /// Called when controlled adjoint Microsoft.Quantum.Intrinsic.T is called in Q#. + /// When this is invoked, it is expected that the T† gate gets applied to controlled on . The gate is given by matrix T†=((1,0),(0,𝑒𝑥𝑝(-𝑖⋅π/4))). + /// + /// + /// When adjoint of Controlled T† is called in Q#, is called. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Qubit to which the gate should be applied. + void ControlledTAdjoint(IQArray controls, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.R is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(-𝑖⋅/2) gets applied to . + /// + /// + /// When adjoint of R is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R(Pauli axis, double theta, Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(-𝑖⋅/2) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled R is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅π⋅/2^) gets applied to . + /// + /// + /// When adjoint of RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void RFrac(Pauli axis, long numerator, long power, Qubit qubit); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.RFrac is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅π⋅/2^) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Pauli operator to be exponentiated to form the rotation. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.R1 is called in Q#. + /// When this is invoked, it is expected that the gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) gets applied to . + /// + /// + /// When adjoint of R1 is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R1(double theta, Qubit qubit); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.R is called in Q#. + /// When this is invoked, it is expected that the gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅))) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled R1 is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Angle about which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR1(IQArray controls, double theta, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// When this is invoked, it is expected that the gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) gets applied to . + /// + /// + /// When adjoint of R1Frac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void R1Frac(long numerator, long power, Qubit qubit); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.R1Frac is called in Q#. + /// When this is invoked, it is expected that the gate given by matrix ((1,0),(0,𝑒𝑥𝑝(𝑖⋅π⋅/2^))) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled RFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Numerator in the dyadic fraction representation of the angle by which the qubit is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit is to be rotated. + /// Qubit to which the gate should be applied. + void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅) gets applied to . + /// + /// + /// When adjoint of Exp is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void Exp(IQArray paulis, double theta, IQArray qubits); + + /// + /// Called when a controlled Microsoft.Quantum.Intrinsic.Exp is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled Exp is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Angle about the given multi-qubit Pauli operator by which the target register is to be rotated. + /// Register to apply the exponent to. + void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅π⋅/2^) gets applied to . + /// + /// + /// When adjoint of ExpFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits); + + /// + /// Called when controlled Microsoft.Quantum.Intrinsic.ExpFrac is called in Q#. + /// When this is invoked, it is expected that the 𝑒𝑥𝑝(𝑖⋅π⋅/2^) gets applied to controlled on . + /// + /// + /// When adjoint of Controlled ExpFrac is called in Q#, is called with replaced by -. + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// The array of qubits on which the operation is controlled. + /// Array of single-qubit Pauli values representing a multi-qubit Pauli to be applied. + /// Numerator in the dyadic fraction representation of the angle by which the qubit register is to be rotated. + /// Power of two specifying the denominator of the angle by which the qubit register is to be rotated. + /// Register to apply the exponent to. + void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.M is called in Q#. + /// When this is invoked, it is expected that the is measured in Z basis, in other words in the computational basis. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . + /// + /// Qubit to which the gate should be applied. + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result M(Qubit qubit); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Measure is called in Q#. + /// When this is invoked, it is expected that the multi-qubit Pauli observable given by is measured on . + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// Class implementing interface can return any class derived from . + /// + /// Qubits to which the gate should be applied. + /// Array of single-qubit Pauli values describing multi-qubit Pauli observable. + /// Zero if the +1 eigenvalue is observed, and One if the -1 eigenvalue is observed. + Result Measure(IQArray bases, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Reset is called in Q#. + /// When this is invoked, it is expected that the is measured and ensured to be in the |0⟩ state such that it can be safely released. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// Qubit to which the gate should be applied. + void Reset(Qubit qubit); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when a conditional statement on measurement results is invoked. + /// + /// The actual results of the measurements of a number of qubits upon which branching is to be performed. + /// The expected values of results of the measurements of these qubits. + /// A value representing this conditional statement and encoding the result of condition. + /// + /// A typical implementation will compare all to and return the result of this comparison. + /// + long StartConditionalStatement(IQArray measurementResults, IQArray resultsValues); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when a conditional statement on a measurement result is invoked. + /// + /// The actual result of the measurement of a qubit upon which branching is to be performed. + /// The expected value of result of the measurement of this qubit. + /// A value representing this conditional statement and encoding the result of the condition. It will be passed through to the other branching related APIs such as RunThenClause. + /// + /// A typical implementation will compare to and return the result of this comparison. + /// + long StartConditionalStatement(Result measurementResult, Result resultValue); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when the "then" statement of a conditional statement is about to be executed. + /// + /// A value representing this conditional statement and encoding the result of condition. + /// If true is returned, the "then" statement will be executed, otherwise it will be skipped and RepeatThenClause will not be called. + /// + /// A typical implementation will use to return whether condition was evaluated to true. + /// + bool RunThenClause(long statement); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when the "then" statement of a conditional statement has finished executing. + /// + /// A value representing this conditional statement and encoding the result of the condition. This is the value returned from the StartConditionalStatement. + /// If true is returned, the "then" statement will be executed again (without calling RunThenClause), folowed by another call to RepeatThenClause. + /// + /// A typical implementation will return false. + /// + bool RepeatThenClause(long statement); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when the "else" statement of a conditional statement is about to be executed. + /// + /// A value representing this conditional statement and encoding the result of the condition. This is the value returned from the StartConditionalStatement. + /// If true is returned, the "else" statement will be executed, otherwise it will be skipped and RepeatElseClause will not be called. + /// + /// A typical implementation will use to return whether condition was evaluated to false. + /// + bool RunElseClause(long statement); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when the "else" statement of a conditional statement has finished executing. + /// + /// A value representing this conditional statement and encoding the result of the condition. This is the value returned from the StartConditionalStatement. + /// If true is returned, the "else" statement will be executed again (without calling RunElseClause), folowed by another call to RepeatElseClause. + /// + /// A typical implementation will return false. + /// + bool RepeatElseClause(long statement); + + /// + /// Intended for a limited support of branching upon measurement results on a target machine level. + /// Called when a conditional statement on measurement results has finished executing. + /// + /// A value representing this conditional statement and encoding the result of the condition. This is the value returned from the StartConditionalStatement. + /// + /// A typical implementation will clean up any data structures associated with statement. + /// + void EndConditionalStatement(long statement); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// + /// + /// The names and the order of the parameters are the same as for the corresponding Q# operation. + /// + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The expected result of Measure(bases, qubits) + /// A message to be reported if the assertion fails. + void Assert(IQArray bases, IQArray qubits, Result result, string msg); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Assert is called in Q#. + /// + /// + /// The names and the order of the parameters is similar to the corresponding Q# operation./ + /// + /// A multi-qubit Pauli operator, for which the measurement outcome is asserted. + /// A register on which to make the assertion. + /// The probability with which result Zero is expected. + /// A message to be reported if the assertion fails. + /// The precision with which the probability of Zero outcome is specified. + void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol); + + /// + /// Called before a call to any Q# operation. + /// + /// Information about operation being called. + /// Information about the arguments passed to the operation. + /// + /// Implement this interface if you want to be notified every time a Q# operation starts. + /// To get the fully qualified Q# name of operation being called use . + /// For the variant of operation, that is to find if Adjoint, Controlled or Controlled Adjoint being called use . + /// To get a sequence of all qubits passed to the operation use . + /// + void OnOperationStart(ICallable operation, IApplyData arguments); + + /// + /// Called when returning from a call to any Q# operation. + /// + /// Information about operation being called. + /// Information about the arguments passed to the operation. + /// + /// Implement this interface if you want to be notified every time a Q# operation ends. + /// To get the fully qualified Q# name of operation being called use . + /// For the variant of operation, that is to find if Adjoint, Controlled or Controlled Adjoint being called use . + /// To get a sequence of all qubits passed to the operation use . + /// + void OnOperationEnd(ICallable operation, IApplyData arguments); + + /// + /// Called when an exception occurs. This could be Fail statement in Q#, or any other exception. + /// + /// Information about exception that was raised. + /// + /// + void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo); + + /// + /// Called when qubits are allocated by Q# using block. + /// + /// Qubits that are being allocated. + /// + /// Every qubit has a unique identifier . + /// All newly allocated qubits are in |0⟩ state. + /// + void OnAllocateQubits(IQArray qubits); + + /// + /// Called when qubits are released in Q# in the end of using block. + /// + /// Qubits that are being released. + /// + /// Every qubit has a unique identifier . + /// All qubits are expected to be released in |0⟩ state. + /// + void OnReleaseQubits(IQArray qubits); + + /// + /// Called when qubits are borrowed by Q# borrowing block. + /// + /// Qubits that are being borrowed. + /// + /// Every qubit has a unique identifier . + /// Borrowed qubits can be in any state. + /// + void OnBorrowQubits(IQArray qubits); + + /// + /// Called when qubits are returned in the end of Q# borrowing block. + /// + /// Qubits that have been borrowed and are now being returned. + /// + /// Every qubit has a unique identifier . + /// Borrowed qubits are expected to be returned in the same state as the state they have been borrowed in. + /// + void OnReturnQubits(IQArray qubits); + + /// + /// Called when + /// Microsoft.Quantum.Diagnostics.DumpMachine + /// is called in Q#. + /// + /// + /// The names and the order of the parameters are similar to corresponding Q# operation. + /// + /// + /// Provides information on where to generate the DumpMachine state. + void OnDumpMachine(T location); + + /// + /// Called when + /// Microsoft.Quantum.Diagnostics.DumpRegister + /// is called in Q#. + /// + /// + /// The names and the order of the parameters are similar to corresponding Q# operation. + /// + /// + /// Provides information on where to generate the DumpRegister state. + /// The list of qubits to report. + void OnDumpRegister(T location, IQArray qubits); + + /// + /// Called when Microsoft.Quantum.Intrinsic.Message is called in Q#. + /// + /// + /// The names and the order of the parameters are the same as corresponding Q# operations. + /// + /// The message to be reported. + void OnMessage(string msg); + } +} diff --git a/src/Simulation/Common/QuantumProcessorBase.cs b/src/Simulation/Common/QuantumProcessorBase.cs new file mode 100644 index 00000000000..00ca208c33c --- /dev/null +++ b/src/Simulation/Common/QuantumProcessorBase.cs @@ -0,0 +1,285 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; +using System.Diagnostics; + +namespace Microsoft.Quantum.Simulation.Common +{ + /// + /// A class that implements IQuantumProcessor that does not do any logic, but is convenient to inherit from. + /// It throws for most APIs. + /// + public class QuantumProcessorBase : IQuantumProcessor + { + public virtual void X(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledX(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Y(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledY(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Z(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledZ(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void SWAP(Qubit qubit1, Qubit qubit2) + { + throw new NotImplementedException(); + } + + public virtual void ControlledSWAP(IQArray controls, Qubit qubit1, Qubit qubit2) + { + throw new NotImplementedException(); + } + + public virtual void H(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledH(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void S(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledS(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void SAdjoint(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledSAdjoint(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void T(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledT(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void TAdjoint(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledTAdjoint(IQArray controls, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void R(Pauli axis, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR(IQArray controls, Pauli axis, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void RFrac(Pauli axis, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledRFrac(IQArray controls, Pauli axis, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void R1(double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR1(IQArray controls, double theta, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void R1Frac(long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void ControlledR1Frac(IQArray controls, long numerator, long power, Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual void Exp(IQArray paulis, double theta, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ControlledExp(IQArray controls, IQArray paulis, double theta, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ExpFrac(IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void ControlledExpFrac(IQArray controls, IQArray paulis, long numerator, long power, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual Result M(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual Result Measure(IQArray bases, IQArray qubits) + { + throw new NotImplementedException(); + } + + public virtual void Reset(Qubit qubit) + { + throw new NotImplementedException(); + } + + public virtual long StartConditionalStatement(IQArray measurementResults, IQArray resultsValues) + { + Debug.Assert(measurementResults.Count == resultsValues.Count); + + int equal = 1; + + for (int i = 0; i < measurementResults.Count; i++) + { + if (measurementResults[i] != resultsValues[i]) + { + equal = 0; + } + } + + return equal; + } + + public virtual long StartConditionalStatement(Result measurementResult, Result resultValue) + { + + if (measurementResult == resultValue) + { + return 1; + } + else + { + return 0; + } + } + + public virtual bool RunThenClause(long statement) + { + return (statement != 0); + } + + public virtual bool RepeatThenClause(long statement) + { + return false; + } + + public virtual bool RunElseClause(long statement) + { + return (statement == 0); + } + + public virtual bool RepeatElseClause(long statement) + { + return false; + } + + public virtual void EndConditionalStatement(long id) + { + + } + + public virtual void Assert(IQArray bases, IQArray qubits, Result result, string msg) + { + } + + public virtual void AssertProb(IQArray bases, IQArray qubits, double probabilityOfZero, string msg, double tol) + { + } + + public virtual void OnOperationStart(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnOperationEnd(ICallable operation, IApplyData arguments) + { + } + + public virtual void OnFail(System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo) + { + } + + public virtual void OnAllocateQubits(IQArray qubits) + { + } + + public virtual void OnReleaseQubits(IQArray qubits) + { + } + + public virtual void OnBorrowQubits(IQArray qubits) + { + } + + public virtual void OnReturnQubits(IQArray qubits) + { + } + + public virtual void OnDumpMachine(T location) + { + } + + public virtual void OnDumpRegister(T location, IQArray qubits) + { + } + + public virtual void OnMessage(string msg) + { + } + + } +} diff --git a/src/Simulation/Common/Utils.cs b/src/Simulation/Common/Utils.cs new file mode 100644 index 00000000000..752c4048dcd --- /dev/null +++ b/src/Simulation/Common/Utils.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Quantum.Simulation.Common +{ + public class CommonUtils + { + /// + /// Removes PauliI terms from observable and corresponding qubits from qubits. + /// Returns the observable description that is equivalent to the original one, but has no PauliI terms + /// + public static void PruneObservable(IQArray observable, IQArray qubits, out QArray prunedObservable, out QArray prunedQubits) + { + Debug.Assert(observable != null); + Debug.Assert(qubits != null); + Debug.Assert(observable.Length == qubits.Length); + prunedObservable = new QArray(PrunedSequence(observable, Pauli.PauliI, observable)); + prunedQubits = new QArray(PrunedSequence(observable, Pauli.PauliI, qubits)); + } + + /// + /// Returns IEnumerable<T> that contains sub-sequence of [i], such that [i] is not equal to . + /// + public static IEnumerable PrunedSequence(IQArray sequence, U value, IQArray sequenceToPrune ) + { + for (uint i = 0; i < sequence.Length; ++i) + { + if (!sequence[i].Equals(value)) + { + yield return sequenceToPrune[i]; + } + } + } + + /// + /// Converts numbers of the form /2^ into canonical form where is odd or zero. + /// If is zero, must also be zero in the canonical form. + /// + public static (long, long) Reduce(long numerator, long denominatorPower) + { + if (numerator == 0) + { + return (0, 0); + } + + if (numerator % 2 != 0) + { + return (numerator, denominatorPower); + } + + long numNew = numerator; + long denomPowerNew = denominatorPower; + + while (numNew % 2 == 0) + { + numNew /= 2; + denomPowerNew -= 1; + } + + return (numNew, denomPowerNew); + } + } +} diff --git a/src/Simulation/Core/QArray.cs b/src/Simulation/Core/QArray.cs index 450fb93253a..de9db576c88 100644 --- a/src/Simulation/Core/QArray.cs +++ b/src/Simulation/Core/QArray.cs @@ -329,6 +329,7 @@ IEnumerable IApplyData.Qubits /// and ArgumentOutOfRangeException. /// /// The long index of the element to access + /// New value of the element /// The element public QArray Modify(long index, T value) { @@ -351,7 +352,8 @@ public QArray Modify(long index, T value) /// or if an index is outside the array bounds, it throws /// and ArgumentOutOfRangeException. /// - /// The long index of the element to access + /// The range of indices of the elements to access + /// New values of the elements /// The element public QArray Modify(QRange indices, IQArray values) { @@ -566,7 +568,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } /// - /// Reads the QArray<> + /// Reads the /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { diff --git a/src/Simulation/Simulators/QuantumProcessor/Allocate.cs b/src/Simulation/Simulators/QuantumProcessor/Allocate.cs new file mode 100644 index 00000000000..ea176410f61 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Allocate.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherAllocate : Intrinsic.Allocate + { + private readonly QuantumProcessorDispatcher sim; + public QuantumProcessorDispatcherAllocate(QuantumProcessorDispatcher m) : base(m){ + sim = m; + } + + public override Qubit Apply() + { + IQArray qubits = sim.QubitManager.Allocate(1); + sim.QuantumProcessor.OnAllocateQubits(qubits); + return qubits[0]; + } + + public override IQArray Apply(long count) + { + IQArray qubits = sim.QubitManager.Allocate(count); + sim.QuantumProcessor.OnAllocateQubits(qubits); + return qubits; + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumProcessor/Assert.cs b/src/Simulation/Simulators/QuantumProcessor/Assert.cs new file mode 100644 index 00000000000..d60f8bcef4e --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Assert.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherAssert : Quantum.Intrinsic.Assert + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherAssert(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray, Result, string), QVoid> Body => (_args) => + { + var (paulis, qubits, result, msg) = _args; + if (paulis.Length != qubits.Length) + { + IgnorableAssert.Assert((paulis.Length != qubits.Length), "Arrays length mismatch"); + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumProcessor.Assert(newPaulis, newQubits, result, msg); + + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, Result, string), QVoid> AdjointBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, string)), QVoid> ControlledBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, string)), QVoid> ControlledAdjointBody => (_args) => { return QVoid.Instance; }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/AssertProb.cs b/src/Simulation/Simulators/QuantumProcessor/AssertProb.cs new file mode 100644 index 00000000000..8d7d31eb8b3 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/AssertProb.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherAssertProb : Quantum.Intrinsic.AssertProb + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherAssertProb(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray, Result, double, string, double), QVoid> Body => (_args) => + { + var (paulis, qubits, result, expectedPr, msg, tol) = _args; + if (paulis.Length != qubits.Length) + { + IgnorableAssert.Assert((paulis.Length != qubits.Length), "Arrays length mismatch"); + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + double probabilityOfZero = result == Result.Zero ? expectedPr : 1.0 - expectedPr; + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumProcessor.AssertProb(newPaulis, newQubits, probabilityOfZero, msg, tol ); + return QVoid.Instance; + }; + + public override Func<(IQArray, IQArray, Result, double, string, double), QVoid> AdjointBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, double, string, double)), QVoid> ControlledBody => (_args) => { return QVoid.Instance; }; + + public override Func<(IQArray, (IQArray, IQArray, Result, double, string, double)), QVoid> ControlledAdjointBody => (_args) => { return QVoid.Instance; }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Borrow.cs b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs new file mode 100644 index 00000000000..bc68f6be23d --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Borrow.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherBorrow : Intrinsic.Borrow + { + private readonly QuantumProcessorDispatcher sim; + public QuantumProcessorDispatcherBorrow(QuantumProcessorDispatcher m) : base(m){ + sim = m; + } + + public override Qubit Apply() + { + IQArray qubits = sim.QubitManager.Borrow(1); + sim.QuantumProcessor.OnBorrowQubits(qubits); + return qubits[0]; + } + + public override IQArray Apply(long count) + { + IQArray qubits = sim.QubitManager.Borrow(count); + sim.QuantumProcessor.OnBorrowQubits(qubits); + return qubits; + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs new file mode 100644 index 00000000000..ded65c58b09 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.cs @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +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); break; + case OperationFunctor.ControlledAdjoint: ((IUnitary)(op)).Controlled.Adjoint.Apply(ctrls); break; + } + } + + private static QVoid ExecuteConditionalStatementInternal(QuantumProcessorDispatcher Simulator, + long statement, + ICallable onEqualOp, + ICallable onNonEqualOp, + OperationFunctor type, + IQArray ctrls) + { + bool run; + + run = Simulator.QuantumProcessor.RunThenClause(statement); + while (run) + { + RunClause(onEqualOp, type, ctrls); + run = Simulator.QuantumProcessor.RepeatThenClause(statement); + } + + run = Simulator.QuantumProcessor.RunElseClause(statement); + while (run) + { + RunClause(onNonEqualOp, type, ctrls); + run = Simulator.QuantumProcessor.RepeatElseClause(statement); + } + + 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) + { + long statement = Simulator.QuantumProcessor.StartConditionalStatement(measurementResults, resultsValues); + return ExecuteConditionalStatementInternal(Simulator, + statement, + onEqualOp, + onNonEqualOp, + type, + ctrls); + } + + private static QVoid ExecuteConditionalStatement(QuantumProcessorDispatcher Simulator, + Result measurementResult, + Result resultValue, + ICallable onEqualOp, + ICallable onNonEqualOp, + OperationFunctor type, + IQArray ctrls) + { + 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) => + { + var (measurementResult, onZero, 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) => + { + var (measurementResult, onZero, onOne) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + }; + + public override Func<(Result, IAdjointable, IAdjointable), QVoid> AdjointBody => (q) => + { + var (measurementResult, onZero, onOne) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); + }; + } + + public class QuantumProcessorApplyIfElseC : Extensions.ApplyIfElseIntrinsicC + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorApplyIfElseC(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } + + public override Func<(Result, IControllable, IControllable), QVoid> Body => (q) => + { + var (measurementResult, onZero, onOne) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + }; + + public override Func<(IQArray, (Result, IControllable, IControllable)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Controlled, ctrls); + }; + } + + 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) => + { + var (measurementResult, onZero, onOne) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Body, null); + }; + + public override Func<(Result, IUnitary, IUnitary), QVoid> AdjointBody => (q) => + { + var (measurementResult, onZero, onOne) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Adjoint, null); + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + return ExecuteConditionalStatement(Simulator, measurementResult, Result.Zero, onZero, onOne, OperationFunctor.Controlled, ctrls); + }; + + public override Func<(IQArray, (Result, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => (q) => + { + var (ctrls, (measurementResult, onZero, onOne)) = q; + 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) => + { + var (measurementResults, resultsValues, onEqualOp, 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) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + }; + + public override Func<(IQArray, IQArray, IAdjointable, IAdjointable), QVoid> AdjointBody => (q) => + { + var (measurementResults, resultsValues, onEqualOp, 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) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + }; + + public override Func<(IQArray, (IQArray, IQArray, IControllable, IControllable)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + 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) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Body, null); + }; + + public override Func<(IQArray, IQArray, IUnitary, IUnitary), QVoid> AdjointBody => (q) => + { + var (measurementResults, resultsValues, onEqualOp, onNonEqualOp) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Adjoint, null); + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.Controlled, ctrls); + }; + + public override Func<(IQArray, (IQArray, IQArray, IUnitary, IUnitary)), QVoid> ControlledAdjointBody => (q) => + { + var (ctrls, (measurementResults, resultsValues, onEqualOp, onNonEqualOp)) = q; + return ExecuteConditionalStatement(Simulator, measurementResults, resultsValues, onEqualOp, onNonEqualOp, OperationFunctor.ControlledAdjoint, ctrls); + }; + } + + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.qs b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.qs new file mode 100644 index 00000000000..f9bd481641d --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/ClassicalControl.qs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.QuantumProcessor.Extensions +{ + open Microsoft.Quantum.Intrinsic; + + operation NoOp() : Unit is Ctl + Adj {} + + // Private helper operations. + operation Delay<'T>(op : ('T => Unit), arg : 'T, aux : Unit) : Unit { + op(arg); + } + + operation DelayC<'T>(op : ('T => Unit is Ctl), arg : 'T, aux : Unit) : Unit is Ctl { + op(arg); + } + + operation DelayA<'T>(op : ('T => Unit is Adj), arg : 'T, aux : Unit) : Unit is Adj { + op(arg); + } + + operation DelayCA<'T>(op : ('T => Unit is Ctl + Adj), arg : 'T, aux : Unit) : Unit is Ctl + Adj { + op(arg); + } + + + // 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 { + body intrinsic; + adjoint intrinsic; + } + + operation ApplyIfElseIntrinsicC(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl) , onResultOneOp : (Unit => Unit is Ctl)) : Unit { + body intrinsic; + controlled intrinsic; + } + + operation ApplyIfElseIntrinsicCA(measurementResult : Result, onResultZeroOp : (Unit => Unit is Ctl + Adj) , onResultOneOp : (Unit => Unit is Ctl + Adj)) : Unit { + body intrinsic; + adjoint intrinsic; + controlled intrinsic; + controlled adjoint intrinsic; + } + + + // Private helper operations. + operation ApplyConditionallyIntrinsic(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit) , onNonEqualOp : (Unit => Unit)) : Unit { + body intrinsic; + } + + operation ApplyConditionallyIntrinsicA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Adj) , onNonEqualOp : (Unit => Unit is Adj)) : Unit is Adj { + body intrinsic; + adjoint intrinsic; + } + + operation ApplyConditionallyIntrinsicC(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl) , onNonEqualOp : (Unit => Unit is Ctl)) : Unit is Ctl { + body intrinsic; + controlled intrinsic; + } + + operation ApplyConditionallyIntrinsicCA(measurementResults : Result[], resultsValues : Result[], onEqualOp : (Unit => Unit is Ctl + Adj) , onNonEqualOp : (Unit => Unit is Ctl + Adj)) : Unit is Ctl + Adj { + body intrinsic; + adjoint intrinsic; + controlled intrinsic; + controlled adjoint intrinsic; + } + + + // 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 { + let zeroOp = Delay(onResultZeroOp, zeroArg, _); + let oneOp = Delay(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfElseRA<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj), oneArg : 'U)) : Unit is Adj { + let zeroOp = DelayA(onResultZeroOp, zeroArg, _); + let oneOp = DelayA(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfElseRC<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Ctl), oneArg : 'U)) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp, zeroArg, _); + let oneOp = DelayC(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfElseCA<'T,'U>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj + Ctl), zeroArg : 'T) , (onResultOneOp : ('U => Unit is Adj + Ctl), oneArg : 'U)) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp, zeroArg, _); + let oneOp = DelayCA(onResultOneOp, oneArg, _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); + } + + + // 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 { + let zeroOp = Delay(onResultZeroOp, zeroArg, _); + let oneOp = Delay(NoOp, (), _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfZeroA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Adj), zeroArg : 'T)) : Unit is Adj{ + let zeroOp = DelayA(onResultZeroOp, zeroArg, _); + let oneOp = DelayA(NoOp, (), _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfZeroC<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl), zeroArg : 'T)) : Unit is Ctl { + let zeroOp = DelayC(onResultZeroOp, zeroArg, _); + let oneOp = DelayC(NoOp, (), _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfZeroCA<'T>(measurementResult : Result, (onResultZeroOp : ('T => Unit is Ctl + Adj), zeroArg : 'T)) : Unit is Ctl + Adj { + let zeroOp = DelayCA(onResultZeroOp, zeroArg, _); + let oneOp = DelayCA(NoOp, (), _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); + } + + + // 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 { + let oneOp = Delay(onResultOneOp, oneArg, _); + let zeroOp = Delay(NoOp, (), _); + ApplyIfElseIntrinsic(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfOneA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Adj), oneArg : 'T)) : Unit is Adj { + let oneOp = DelayA(onResultOneOp, oneArg, _); + let zeroOp = DelayA(NoOp, (), _); + ApplyIfElseIntrinsicA(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfOneC<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl), oneArg : 'T)) : Unit is Ctl { + let oneOp = DelayC(onResultOneOp, oneArg, _); + let zeroOp = DelayC(NoOp, (), _); + ApplyIfElseIntrinsicC(measurementResult, zeroOp, oneOp); + } + + operation ApplyIfOneCA<'T>(measurementResult : Result, (onResultOneOp : ('T => Unit is Ctl + Adj), oneArg : 'T)) : Unit is Ctl + Adj { + let oneOp = DelayCA(onResultOneOp, oneArg, _); + let zeroOp = DelayCA(NoOp, (), _); + ApplyIfElseIntrinsicCA(measurementResult, zeroOp, oneOp); + } + + + // 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 { + let equalOp = Delay(onEqualOp,equalArg,_); + let nonEqualOp = Delay(onNonEqualOp,nonEqualArg,_); + ApplyConditionallyIntrinsic(measurementResults, resultsValues, equalOp, nonEqualOp); + } + + operation ApplyConditionallyA<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Adj), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Adj), nonEqualArg : 'U)) : Unit is Adj { + let equalOp = DelayA(onEqualOp, equalArg, _); + let nonEqualOp = DelayA(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicA(measurementResults, resultsValues, equalOp, nonEqualOp); + } + + operation ApplyConditionallyC<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Ctl), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Ctl), nonEqualArg : 'U)) : Unit is Ctl { + let equalOp = DelayC(onEqualOp, equalArg, _); + let nonEqualOp = DelayC(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicC(measurementResults, resultsValues, equalOp, nonEqualOp); + } + + operation ApplyConditionallyCA<'T,'U>(measurementResults : Result[], resultsValues : Result[], (onEqualOp : ('T => Unit is Ctl + Adj), equalArg : 'T) , (onNonEqualOp : ('U => Unit is Ctl + Adj), nonEqualArg : 'U)) : Unit is Ctl + Adj { + let equalOp = DelayCA(onEqualOp, equalArg, _); + let nonEqualOp = DelayCA(onNonEqualOp, nonEqualArg, _); + ApplyConditionallyIntrinsicCA(measurementResults, resultsValues, equalOp, nonEqualOp); + } + +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Dump.cs b/src/Simulation/Simulators/QuantumProcessor/Dump.cs new file mode 100644 index 00000000000..a0b2ce227f7 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Dump.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherDumpMachine : Quantum.Diagnostics.DumpMachine + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherDumpMachine(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (location) => + { + if (location == null) { throw new ArgumentNullException(nameof(location)); } + + this.Simulator.QuantumProcessor.OnDumpMachine(location); + return QVoid.Instance; + }; + } + + public class QuantumProcessorDispatcherDumpRegister : Quantum.Diagnostics.DumpRegister + { + private QuantumProcessorDispatcher Simulator { get; } + + + public QuantumProcessorDispatcherDumpRegister(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(T, IQArray), QVoid> Body => (__in) => + { + var (location, qubits) = __in; + + if (location == null) { throw new ArgumentNullException(nameof(location)); } + this.Simulator.QuantumProcessor.OnDumpRegister(location, qubits); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Exp.cs b/src/Simulation/Simulators/QuantumProcessor/Exp.cs new file mode 100644 index 00000000000..90f981a996b --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Exp.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherExp : Quantum.Intrinsic.Exp + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherExp(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, double, IQArray), QVoid> Body => (_args) => + { + var (paulis, theta, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumProcessor.Exp(newPaulis, theta, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, double, IQArray), QVoid> AdjointBody => (_args) => + { + var (paulis, angle, qubits) = _args; + return this.Body.Invoke((paulis, -angle, qubits)); + }; + + public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledBody => (_args) => + { + var (ctrls, (paulis, theta, qubits)) = _args; + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumProcessor.ControlledExp(ctrls, newPaulis, theta, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, double, IQArray)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (paulis, angle, qubits)) = _args; + + return this.ControlledBody.Invoke((ctrls, (paulis, -angle, qubits))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/ExpFrac.cs b/src/Simulation/Simulators/QuantumProcessor/ExpFrac.cs new file mode 100644 index 00000000000..5d9eda03e5a --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/ExpFrac.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; +using System; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherExpFrac : Quantum.Intrinsic.ExpFrac + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherExpFrac(QuantumProcessorDispatcher m) : base(m) { this.Simulator = m; } + + public override Func<(IQArray, long, long, IQArray), QVoid> Body => (_args) => + { + var (paulis, nom, den, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException( + $"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + + Simulator.QuantumProcessor.ExpFrac(newPaulis, nom, den, newQubits); + return QVoid.Instance; + }; + + public override Func<(IQArray, long, long, IQArray), QVoid> AdjointBody => (_args) => + { + var (paulis, nom, den, qubits) = _args; + return this.Body.Invoke((paulis, -nom, den, qubits)); + }; + + public override Func<(IQArray, (IQArray, long, long, IQArray)), QVoid> + ControlledBody => (_args) => + { + var (ctrls, (paulis, nom, den, qubits)) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException( + $"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size."); + } + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + Simulator.QuantumProcessor.ControlledExpFrac(ctrls, newPaulis, nom, den, newQubits); + + return QVoid.Instance; + }; + + public override Func<(IQArray, (IQArray, long, long, IQArray)), QVoid> + ControlledAdjointBody => (_args) => + { + var (ctrls, (paulis, nom, den, qubits)) = _args; + + return this.ControlledBody.Invoke((ctrls, (paulis, -nom, den, qubits))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/H.cs b/src/Simulation/Simulators/QuantumProcessor/H.cs new file mode 100644 index 00000000000..e92bb13f6e2 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/H.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherH : Quantum.Intrinsic.H + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherH(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.H(q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (args) => + { + var (ctrls, q1) = args; + Simulator.QuantumProcessor.ControlledH(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/M.cs b/src/Simulation/Simulators/QuantumProcessor/M.cs new file mode 100644 index 00000000000..adf46ea18ef --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/M.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherM : Quantum.Intrinsic.M + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherM(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q) => + { + return Simulator.QuantumProcessor.M(q); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Measure.cs b/src/Simulation/Simulators/QuantumProcessor/Measure.cs new file mode 100644 index 00000000000..04b93b71162 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Measure.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherMeasure : Quantum.Intrinsic.Measure + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherMeasure(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(IQArray, IQArray), Result> Body => (_args) => + { + var (paulis, qubits) = _args; + + if (paulis.Length != qubits.Length) + { + throw new InvalidOperationException($"Both input arrays for {this.GetType().Name} (paulis,qubits), must be of same size"); + } + + CommonUtils.PruneObservable(paulis, qubits, out QArray newPaulis, out QArray newQubits); + return Simulator.QuantumProcessor.Measure( newPaulis, newQubits); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs new file mode 100644 index 00000000000..54d937add40 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/QuantumProcessorDispatcher.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + /// + /// Dispatcher (Simulator) that redirects all the calls to a class implementing interface. + /// + public partial class QuantumProcessorDispatcher : SimulatorBase + { + private const int PreallocatedQubitCount = 256; + /// + /// Random number generator used for Microsoft.Quantum.Intrinsic.Random + /// + public readonly System.Random random; + + public override string Name => "QuantumProcessorDispatcher"; + + /// + /// An instance of a class implementing interface that this simulator wraps. + /// + public IQuantumProcessor QuantumProcessor + { + get; + private set; + } + + /// + /// + /// + /// An instance of a class implementing interface to be wrapped. If the parameter is null is used. + /// An instance of a class implementing interface. If the parameter is null is used. + /// A seed to be used by Q# Microsoft.Quantum.Intrinsic.Random operation. + public QuantumProcessorDispatcher(IQuantumProcessor quantumProcessor = null, IQubitManager qubitManager = null, int? randomSeed = null) + : base(qubitManager ?? new QubitManagerTrackingScope(PreallocatedQubitCount, mayExtendCapacity:true, disableBorrowing:false)) + { + random = new System.Random(randomSeed == null ? DateTime.Now.Millisecond : randomSeed.Value); + QuantumProcessor = quantumProcessor ?? new QuantumProcessorBase(); + OnOperationStart += QuantumProcessor.OnOperationStart; + OnOperationEnd += QuantumProcessor.OnOperationEnd; + OnFail += QuantumProcessor.OnFail; + OnLog += QuantumProcessor.OnMessage; + } + + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/R.cs b/src/Simulation/Simulators/QuantumProcessor/R.cs new file mode 100644 index 00000000000..cd3307d2acf --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/R.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherR : Quantum.Intrinsic.R + { + private QuantumProcessorDispatcher Simulator { get; } + + + public QuantumProcessorDispatcherR(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Pauli, double, Qubit), QVoid> Body => (_args) => + { + var (basis, angle, q1) = _args; + if (basis != Pauli.PauliI) + { + Simulator.QuantumProcessor.R(basis, angle,q1); + } + return QVoid.Instance; + }; + + public override Func<(Pauli, double, Qubit), QVoid> AdjointBody => (_args) => + { + var (basis, angle, q1) = _args; + return this.Body.Invoke((basis, -angle, q1)); + }; + + public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledBody => (_args) => + { + var (ctrls, (basis, angle, q1)) = _args; + Simulator.QuantumProcessor.ControlledR(ctrls, basis, angle, q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, (Pauli, double, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (basis, angle, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (basis, -angle, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/R1.cs b/src/Simulation/Simulators/QuantumProcessor/R1.cs new file mode 100644 index 00000000000..401caf9f380 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/R1.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherR1 : Quantum.Intrinsic.R1 + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherR1(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(double, Qubit), QVoid> Body => (_args) => + { + var (angle, q1) = _args; + Simulator.QuantumProcessor.R1(angle, q1); + return QVoid.Instance; + }; + + public override Func<(double, Qubit), QVoid> AdjointBody => (_args) => + { + var (angle, q1) = _args; + return this.Body.Invoke((-angle, q1)); + }; + + public override Func<(IQArray, ( double, Qubit)), QVoid> ControlledBody => (_args) => + { + var (ctrls, (angle, q1)) = _args; + Simulator.QuantumProcessor.ControlledR1(ctrls, angle, q1); + return QVoid.Instance; + }; + + + public override Func<(IQArray, (double, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (angle, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (-angle, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/R1Frac.cs b/src/Simulation/Simulators/QuantumProcessor/R1Frac.cs new file mode 100644 index 00000000000..64808e823ad --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/R1Frac.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherR1Frac : Quantum.Intrinsic.R1Frac + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherR1Frac(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(long, long, Qubit), QVoid> Body => (_args) => + { + var (num, denom , q1) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumProcessor.R1Frac(numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(long, long, Qubit), QVoid> AdjointBody => (_args) => + { + var (num, denom, q1) = _args; + return this.Body.Invoke((-num, denom, q1)); + }; + + public override Func<(IQArray, (long, long, Qubit)), QVoid> ControlledBody => (_args) => + { + var (ctrls, (num, denom, q1)) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumProcessor.ControlledR1Frac(ctrls, numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, (long, long, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (num, denom, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (-num, denom, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/RFrac.cs b/src/Simulation/Simulators/QuantumProcessor/RFrac.cs new file mode 100644 index 00000000000..6164863b740 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/RFrac.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Common; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherRFrac : Quantum.Intrinsic.RFrac + { + + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherRFrac(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Pauli, long, long, Qubit), QVoid> Body => (_args) => + { + var (basis, num, denom , q1) = _args; + if (basis != Pauli.PauliI) + { + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumProcessor.RFrac(basis, numNew, denomNew, q1); + } + return QVoid.Instance; + }; + + public override Func<(Pauli, long, long, Qubit), QVoid> AdjointBody => (_args) => + { + var (basis, num, denom, q1) = _args; + return this.Body.Invoke((basis, -num, denom, q1)); + }; + + public override Func<(IQArray, (Pauli, long, long, Qubit)), QVoid> ControlledBody => (_args) => + { + var (ctrls, (basis, num, denom, q1)) = _args; + var (numNew, denomNew) = CommonUtils.Reduce(num, denom); + Simulator.QuantumProcessor.ControlledRFrac(ctrls, basis, numNew, denomNew, q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Pauli, long, long, Qubit)), QVoid> ControlledAdjointBody => (_args) => + { + var (ctrls, (basis, num, denom, q1)) = _args; + return this.ControlledBody.Invoke((ctrls, (basis, -num, denom, q1))); + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Release.cs b/src/Simulation/Simulators/QuantumProcessor/Release.cs new file mode 100644 index 00000000000..84424d3daa0 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Release.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherRelease : Intrinsic.Release + { + private readonly QuantumProcessorDispatcher sim; + public QuantumProcessorDispatcherRelease(QuantumProcessorDispatcher m) : base(m){ + sim = m; + } + + public override void Apply(Qubit q) + { + sim.QuantumProcessor.OnReleaseQubits(new QArray(q)); + sim.QubitManager.Release(q); + } + + public override void Apply(IQArray qubits) + { + sim.QuantumProcessor.OnReleaseQubits(qubits); + sim.QubitManager.Release(qubits); + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumProcessor/Reset.cs b/src/Simulation/Simulators/QuantumProcessor/Reset.cs new file mode 100644 index 00000000000..4ebee59437a --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Reset.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherReset : Quantum.Intrinsic.Reset + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherReset(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.Reset(q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Return.cs b/src/Simulation/Simulators/QuantumProcessor/Return.cs new file mode 100644 index 00000000000..db541624ef3 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Return.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + using Microsoft.Quantum.Simulation.Core; + + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherReturn : Intrinsic.Return + { + private readonly QuantumProcessorDispatcher sim; + public QuantumProcessorDispatcherReturn(QuantumProcessorDispatcher m) : base(m){ + sim = m; + } + + public override void Apply(Qubit q) + { + sim.QuantumProcessor.OnReturnQubits(new QArray(q)); + sim.QubitManager.Return(q); + } + + public override void Apply(IQArray qubits) + { + sim.QuantumProcessor.OnReturnQubits(qubits); + sim.QubitManager.Return(qubits); + } + } + } +} \ No newline at end of file diff --git a/src/Simulation/Simulators/QuantumProcessor/S.cs b/src/Simulation/Simulators/QuantumProcessor/S.cs new file mode 100644 index 00000000000..84bac1a1ed9 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/S.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherS : Quantum.Intrinsic.S + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherS(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.S(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumProcessor.ControlledS(ctrls, q1); + return QVoid.Instance; + }; + + public override Func AdjointBody => (q1) => + { + Simulator.QuantumProcessor.SAdjoint(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumProcessor.ControlledSAdjoint(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/SWAP.cs b/src/Simulation/Simulators/QuantumProcessor/SWAP.cs new file mode 100644 index 00000000000..edb95bf4c63 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/SWAP.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherSWAP : Quantum.Intrinsic.SWAP + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherSWAP(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func<(Qubit,Qubit), QVoid> Body => (q1) => + { + Simulator.QuantumProcessor.SWAP(q1.Item1, q1.Item2); + return QVoid.Instance; + }; + + public override Func<(IQArray, (Qubit, Qubit)), QVoid> ControlledBody => (args) => + { + var (ctrls, q1) = args; + Simulator.QuantumProcessor.ControlledSWAP(ctrls, q1.Item1, q1.Item2); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/T.cs b/src/Simulation/Simulators/QuantumProcessor/T.cs new file mode 100644 index 00000000000..e7d7e295ac4 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/T.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherT : Quantum.Intrinsic.T + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherT(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.T(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + + Simulator.QuantumProcessor.ControlledT(ctrls, q1); + + return QVoid.Instance; + }; + + public override Func AdjointBody => (q1) => + { + Simulator.QuantumProcessor.TAdjoint(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledAdjointBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumProcessor.ControlledTAdjoint(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/X.cs b/src/Simulation/Simulators/QuantumProcessor/X.cs new file mode 100644 index 00000000000..1de39069395 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/X.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherX : Quantum.Intrinsic.X + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherX(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.X(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (args) => + { + var (ctrls, q1) = args; + Simulator.QuantumProcessor.ControlledX(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Y.cs b/src/Simulation/Simulators/QuantumProcessor/Y.cs new file mode 100644 index 00000000000..e4a7836c7d5 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Y.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherY : Quantum.Intrinsic.Y + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherY(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.Y(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumProcessor.ControlledY(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/Z.cs b/src/Simulation/Simulators/QuantumProcessor/Z.cs new file mode 100644 index 00000000000..b939d1373ef --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/Z.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public class QuantumProcessorDispatcherZ : Quantum.Intrinsic.Z + { + private QuantumProcessorDispatcher Simulator { get; } + + public QuantumProcessorDispatcherZ(QuantumProcessorDispatcher m) : base(m) + { + this.Simulator = m; + } + + public override Func Body => (q1) => + { + Simulator.QuantumProcessor.Z(q1); + return QVoid.Instance; + }; + + public override Func<(IQArray, Qubit), QVoid> ControlledBody => (_args) => + { + (IQArray ctrls, Qubit q1) = _args; + Simulator.QuantumProcessor.ControlledZ(ctrls, q1); + return QVoid.Instance; + }; + } + } +} diff --git a/src/Simulation/Simulators/QuantumProcessor/random.cs b/src/Simulation/Simulators/QuantumProcessor/random.cs new file mode 100644 index 00000000000..d9c51cfa202 --- /dev/null +++ b/src/Simulation/Simulators/QuantumProcessor/random.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Quantum.Simulation.Core; +using System; + +namespace Microsoft.Quantum.Simulation.QuantumProcessor +{ + public partial class QuantumProcessorDispatcher + { + public static long SampleDistribution(IQArray unnormalizedDistribution, double uniformZeroOneSample) + { + double total = 0.0; + foreach (double prob in unnormalizedDistribution) + { + if (prob < 0) + { + throw new ExecutionFailException("Random expects array of non-negative doubles."); + } + total += prob; + } + + if (total == 0) + { + throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum."); + } + + double sample = uniformZeroOneSample * total; + double sum = unnormalizedDistribution[0]; + for (int i = 0; i < unnormalizedDistribution.Length - 1; ++i) + { + if (sum >= sample) + { + return i; + } + sum += unnormalizedDistribution[i]; + } + return unnormalizedDistribution.Length; + } + + public class QuantumProcessorDispatcherRandom : Quantum.Intrinsic.Random + { + private QuantumProcessorDispatcher Simulator { get; } + public QuantumProcessorDispatcherRandom(QuantumProcessorDispatcher m) : base(m) + { + Simulator = m; + } + + public override Func, Int64> Body => (p) => + { + return SampleDistribution(p, Simulator.random.NextDouble()); + }; + } + } +}