Journey continued
We embarked in a journey to explore the fascinating world of quantum computing. We tasked ourselves to hello world equivalent which is random number generation. In the journey so far, we have worked with qubit and have talked about the concept of superposition and quantum measurement. We have thus far built this
namespace QuantumExperiments { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Measurement; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert;
@Entrypoint() operation GetSuperimposedBit() : Result { use q = Qubit(); H(q); return M(q); } }
|
Now, we move to move on to leveraging the qubit to get the random numbers.
Define random
In the traditional .NET world, you would written a C# code just like this –
int rnd1 = (new Random()).Next();
|
There are few additional features, as in you could control the gap between which the random number is generated by passing additional parameters. But that is about it. In quantum world same is achieved by the heuristics of –
The first part that deciding the maximum is also possible in traditional .NET world –
int rnd2 = (new Random()).Next(10);
|
Now we will have a random number which is not larger than 10. The numbers generated by the approach used by System.Random is pseudo random as documented in official version. Simply because mathematical algorithm is used to generate the number which is practically random enough. If generated for large enough times you could observe a pattern. Thus, random number generation used for securing communications are derived from RNGCryptoServiceProviderclass.
Similar limitation exists in quantum world. However, the randomness is far more secured as algorithm is not used to generate the random numbers. Rather the atom’s state is used to generate that random number. Thus, giving a edge over the classical computer’s (traditional .NET) random number generation.
Implementation
Now let us put this logic to work. We start by bringing the in the namespaces that are required.
open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert;
|
These namespaces are required to perform two important operations in the code we are about to write. One is to calculate the number of bits for a given integer. E.g., the number of bits to represent number 2 is 2 and 5 is 3 and 13 is 4 and number 100 is 8 bits and so on. The important operation that is required from Convert namespace is of converting a bit array into integer. If you notice in our algorithm, we are computing the random bits one by one. Once each bit is computed we would want to convert that to a number which is the decimal equivalent of that binary. No wonder we could implement that logic ourselves, but a framework’s primary purpose is to accelerate development rather that solve only difficult to solve problems, isn’t it?
Let us build code bit by bit; pun intended. We begin with mutable variables. Yes, mutable is a keyword that is required and folks with F# background will connect with the importance of that keyword. So let us declare our operation’s skeleton with the mutable result that is passed out of the operation.
operation RngOps(max : Int) : Int { mutable output = 0; return output; }
|
This skeleton should not prompt any error. Notice we put the datatype after the name of the variable separated by the colon character. Pretty standard in the F# world. We next bring in a bit array this will grow to wider array based on the number of bits required for max parameter passed into the operation. This is done as –
mutable bits = new Result[0];
|
This is a single bit but we will sooner add a loop based on the number of bits required that add single bit in every pass as follows –
for bit in 1..BitSizeI(max) { set bits += [GetSuperimposedBit()]; }
|
The code uses the generator syntax similar to python and obviously F# i.e. 1..N where instead of N we have used a function that gets the bit size for an integer that is passed as parameter. The iteration keeps adding an array element enclosed in square brackets to the bits array. The element that is being added is another operation we defined earlier which gets a value of superimposed bit.
Now we have all the random bits in the bits variable. We however will have to then convert that to decimal value which we can understand that we do using the library operation –
set output = ResultArrayAsInt(bits);
|
Let us put all this together –
open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert;
operation RngOps(max : Int) : Int { mutable output = 0; mutable bits = new Result[0]; for bit in 1..BitSizeI(max) { set bits += [GetSuperimposedBit()]; } return output; }
|
We now setup an EntryPoint just like the main method in a C# program and invoke the operation above –
@EntryPoint() operation Generate() : Result { Message(“Random number below 50 is ”); return RngOps(50); }
|
If you run this method sufficiently long by repeating it you should get random numbers near perfect only. Because remember you are still running this in simulator. You could task yourself to find the pattern. That will be an interesting exercise. However, if you run the program in quantum hardware you can be certain enough to get real random numbers.
We leave another puzzle for you there is a catch to this logic. Give it a try in another dispatch we will reveal that to you. Till then, Happy computing!