Emulation in Q#

Mathias Soeken

Mathias

Sometimes it’s helpful to be able to implement Q# functions or operations directly in C#. This can be used to access some API that is not directly accessible in Q#, or to provide alternative implementations based on the context in which the Q# program is executed. As one example, we might want to use slightly different implementations based on whether the program is executed for resource estimation or for simulation. This blog post describes techniques to programmatically replace a Q# function by another one. For the sake of simplicity, we focus on Q# functions in this post, but the techniques apply to Q# operations analogously. Also, the main goal of this post is to illustrate this feature conceptually, whereas the details of the API may change in the future.

Intrinsic functions

The first technique employs intrinsic functions. It can be used to implement a Q# function using a .NET language, for example C#. This is particularly useful when the required library functionality is not available in Q#. Let’s consider the following example, typical for this season. We often find ourselves in need of the number of the remaining days until Christmas as a value in our Q# operation. This value can be used as the secret shift in the hidden shift algorithm or as the special element in a Grover search. We cannot retrieve the current date in Q#, and therefore we have to provide this function as an intrinsic:

function DaysUntilChristmas() : Int {
    body intrinsic;
}

This Q# code gets translated into a partial C# class called DaysUntilChristmas. We can add the implementation by creating a nested class called Native that derives from DaysUntilChristmas. In its constructor this class accepts an instance m of type IOperationFactory, which is the base class to all simulators. Therefore, m holds the simulator object for which the function is called. This will enable us to perform simulator-dependent code. We’ll use this variable when describing the second technique, however, in this example we compute the same function independent of the simulator.

public partial class DaysUntilChristmas {
    public class Native : DaysUntilChristmas {
        public Native(IOperationFactory m) : base(m) {}

        // can be adjusted (e.g., 1/7, 1/6, 1/19, ...)
        private static int ChristmasMonth => 12;
        private static int ChristmasDay => 25;

        // C# function with matching signature
        private long DaysUntilChristmasFunction(QVoid input) {
            var today = DateTime.Today;
            var christmas = new DateTime(today.Year, ChristmasMonth, ChristmasDay);

            // make sure the next Christmas is today or in the future
            if (christmas < today)
                christmas = christmas.AddYears(1);

            // return difference in days
            return (christmas - today).Days;
        }

        // Override __Body__ property to use C# function
        public override Func __Body__ => DaysUntilChristmasFunction;
    }
}

The function implementation is provided in terms of the __Body__ property, which is of type Func<__In__, __Out__>, where __In__ is the type of the input argument tuple in the Q# function and __Out__ is the type of the output argument tuple. In this case, there are no input arguments, represented by the empty tuple type QVoid, and there is a single output argument of Q# type Int, which corresponds to the C# type long (= Int64).

Overriding functions

We can use a similar technique to replace an existing function with an alternative one. It would be nice to make Q#’s Message outputs a little more festive this month. For this purpose, we implement an intrinsic function called ChristmasMessage:

function ChristmasMessage(msg : String) : Unit {
    body intrinsic;
}

The implementation is provided in C# and it prefixes each message with Santa’s way of expressing his happiness and joy.

public partial class ChristmasMessage {
    public class Native : ChristmasMessage {
        private readonly IOperationFactory simulator;

        public Native(IOperationFactory m) : base(m) {
            simulator = m;
        }

        private QVoid ChristmasMessageFunction(string message) {
            if (simulator is ToffoliSimulator) {
                WriteLine(message);
            } else {
                WriteLine($"Ho ho ho: {message}");
            }

            return QVoid.Instance;
        }

        public override Func __Body__ => ChristmasMessageFunction;
    }
}

Note that we do not override the behavior when using the ToffoliSimulator, since the Toffoli simulator does not support the H in Ho ho ho.

Instead of replacing all occurrences of Message in our Q# programs by hand, we wish to do this automatically and hide the existence of the ChristmasMessage from our users. When constructing a simulator instance in a C# host program, we can use the Register method to replace an existing function with an alternative one.

var simulator = new QuantumSimulator();
simulator.Register(typeof(Message), typeof(ChristmasMessage), typeof(ICallable));

The first parameter is the type of the existing function, in this case Message, the second parameter is the type of the replacement, in this case ChristmasMessage, and the third parameter is the type of either ICallable, IAdjointable, IControllable, or IUnitary. For functions and operations that are neither adjoint nor controlled, use ICallable. For operations that are marked Adj but not Ctl, use IAdjointable, for those marked Ctl but not Adj, use IControllable, and if they have both, use IUnitary.

It’s worth to note that we couldn’t just have implemented ChristmasMessage by calling Message inside and then use Register for the replacement. This would have lead to an infinite recursive loop, since the Message call inside ChristmasMessage would also be replaced.

The same technique can be used to replace one Q# operation by another Q# operation, the replacement operation doesn’t need to be implemented in C#. Consider the following operation that swaps two qubits using three CNOTs:

operation SwapWithCNOTs(a : Qubit, b : Qubit) is Adj+Ctl {
    CNOT(a, b);
    CNOT(b, a);
    CNOT(a, b);
}

To replace the SWAP operation in the Microsoft.Quantum.Intrinsic namespace, we can simply call Register on the simulator like this:

simulator.Register(typeof(SWAP), typeof(SwapWithCNOTs), typeof(IUnitary));

Further reading

The emulation technique was demonstrated for Q# functions in this post, but it applies similarly to Q# operations as well. However, depending on the supported functors (such as Adj and Ctl), operations for __AdjointBody__, __ControlledBody__, and __AdjointControlledBody__ might also need to be implemented.

The technique is used in several places in the Q# and QDK code base. Some examples include:

The complete code for the project can be found in this gist.

It’s DaysUntilChristmas() days until Christmas, ChristmasMessage("Happy holidays!").

Posted in Q#

0 comments

Comments are closed. Login to edit/delete your existing comments