Page 40 - MSDN Magazine, September 2019
P. 40
Figure 9 AliceViewModel.SendAsync Method
Figure 10 AliceViewModel.DispatchItemsInQueue Method
async Task SendAsync(object arg) {
var bytes = Encoding.ASCII.GetBytes(Message);
foreach (byte b in bytes) {
byteQueue.Enqueue(b);
await Messenger.PublishAsync(
new RequestQubitsMessage(qubitsRequiredForByte)); }
Message = string.Empty; }
async Task DispatchItemsInQueue() {
var qOps = Dependency.Resolve<QOperations, QOperations>(true);
while (byteQueue.Any()) {
if (qubitQueue.Count < qubitsRequiredForByte) {
return; }
IList<Qubit> qubits = qubitQueue.DequeueMany(qubitsRequiredForByte).ToList();
byte b = byteQueue.Dequeue();
BitArray bitArray = new BitArray(new[] { b });
/* Convert classical bit pairs to single qubits. */
for (int i = 0, j = 0; i < bitArray.Length; i += 2, j++) {
await qOps.EncodeMessageInQubitAsync( qubits[j],
bitArray[i],
bitArray[i + 1]);
}
await Messenger.PublishAsync(new DecodeQubitsMessage(qubits)); }
}
I’m still chuffed seeing properties written with such conciseness, where a lambda expression combined with a null coalescing oper- ator brings lazy loading in just a couple lines of code.
Codon’s command infrastructure supports async command han- dlers. By using Codon’s AsyncActionCommand, you can specify the async method SendAsync as the command handler.
Alice.razor contains a text field and a button:
<input type=”text” bind=”@ViewModel.Message” /> <button class=”btn btn-primary”
onclick=”@ViewModel.SendCommand.Execute”>Send to Bob</button>
The input box is bound to the view-model’s Message property. When the Send to Bob button is clicked, the view-model’s SendCom- mand executes, and its SendAsync method is called (see Figure 9).
The view-model has a queue that contains the bytes of each mes- sage that’s encoded and sent to Bob. Codon’s IMessenger is used to send off a message, which ultimately reaches Charlie, requesting four qubits be entangled and sent out, two for Alice and two for Bob.
Finally, the Message property is reset to string.empty, which clears the input box and leaves it ready for a new message.
AliceViewModel implements IMessageSubscriber<Alice- QubitMessage> and thus receives all messages of that type:
gasync Task IMessageSubscriber<AliceQubitMessage>.ReceiveMessageAsync( AliceQubitMessage message)
{
foreach (var qubit in message.Qubits) {
qubitQueue.Enqueue(qubit); }
await DispatchItemsInQueue(); }
When ReceiveMessageAsync is called, the payload contains a collection of Qubit instances from Charlie. AliceViewModel also retains a queue of Qubit objects, to which the newly arrived qubits are added.
AliceViewModel is now ready to send at least part of a message to Bob. DispatchItemsInQueue is called, as shown in Figure 10.
DispatchItemsInQueue first retrieves the QOperations instance from the IoC container. Dependency.Resolve<T,T>(bool singleton) causes a new instance to be created if one hasn’t been already. That instance is then retained as a singleton so that future requests will resolve the same object.
An extension method is used to dequeue four qubits from the qubit queue. The message byte is also dequeued and placed into a BitArray. The QOperations object is then tasked with placing each qubit into a superposition representing the 2-bit message. Notice again how one qubit is able to represent two classical bits because its state affects the quantum state of the pair.
Figure 11 ReceiveMessageAsync (DecodeQubitsMessage) Method
async Task IMessageSubscriber<DecodeQubitsMessage>.ReceiveMessageAsync( DecodeQubitsMessage message)
{
IList<Qubit> aliceQubits = message.Qubits;
List<Qubit> bobQubits = qubits.DequeueMany(aliceQubits.Count).ToList();
var qOps = Dependency.Resolve<QOperations, QOperations>(true); var bytes = new List<byte>();
for (int i = 0; i < bobQubits.Count; i += 4) {
byte b = 0;
for (int j = 0; j < 4; j++) {
(bool aliceBit, bool bobBit) = await qOps.DecodeQubits( bobQubits[i + j], aliceQubits[i + j]);
if (bobBit) {
b |= (byte)(1 << (j * 2 + 1)); }
if (aliceBit) {
b |= (byte)(1 << (j * 2)); }
}
bytes.Add(b); }
Message += Encoding.ASCII.GetString(bytes.ToArray());
await Messenger.PublishAsync(new ReleaseQubitsMessage(aliceQubits));
await Messenger.PublishAsync(new ReleaseQubitsMessage(bobQubits)); }
32 msdn magazine
Quantum Computing
The IMessenger is then used to dispatch a DecodeQubits- Message that’s ultimately received by Bob.
Receiving Messages as Bob Like Alice, Bob has a queue of Qubits that arrive from Charlie. BobViewModel implements IMessageSubscriber<BobQubitMessage>. When Charlie sends