Quantum Circuits

One of the nicest properties of quantum computing circuits is the fact that you can achieve the same goal with a fewer number of steps compared to classical computer, and it has been a lot of fun for me to discover how to implement such algorithms.

I wanted to write about an algorithm I spent some time thinking about and wrestling with. This particular quantum circuit does not provide an improvement over a classical one (there are algorithms tacking similar problems that ac tually do provide speed-ups), but it was really nice to see how to solve a problem using quantum thinking as opposed to classical thinking.

The problem consist of coming up with an algorithm to learn the bits of a hidden string s. For this problem we restrict the string s to be a string of 0 and 1, e.g.: 100110

The classical algorithm is quite simple. It can be summarized as follows: test every bit of the string with the and operation and a 1, if the result is 1 then the bit is a 1 otherwise the bit is a 0.

To solve this problem using quantum computing I decided to break the algorithm into two parts. The first part will encode a unitary function whose main purpouse is some information from any secret string. The second part of the algorithm consists in preparing a state that represents all the possible states of a binary string s of size n. The first part of the algorith is called an oracle.

The oracle

As mentioned before, the first part of the problems boils down to finding a quantum circuit that can be used to extract information from any string s. By doing some exploration and due to previous experinece I had on similar problems I settled on the oracle that is would basically calculate the sum mod 2 of $x_i$ * $s_i$ where $x_i$ is the ith bit of an arbitrary string x and $s_i$ is the ith bit of the hidden string s. Or in other words:

$$ (\sum_{i=0}^{n}s_i * x_i)\ mod\ 2 $$

The above is equivalent to calculating the parity of s when x equals to 111...1. Next, then is the problem of coming up with an algorithm that encodes the above unitary, here I did testing of different circuits looking for patterns, starting with smaller strings allowed me to find patters in the circuits. For example the circuit for the string 101 looks like this:

sc2

The pattern I found was basically CNOTing all the 1 bits of the secret string. Thus, I coded up a function whose input is an arbitrary string s and the output is a quantum circuit that encodes the above unitary for the input string s. The width of the circuit varies grows linearly with the length of s(which is not great), and the number of gates grows linearly with the number of 1 in s, they are all CNOT gates which is implemented in most quantum hardware. Further there are no operations between the input qubits, only between the inputs and output qubit.

sc3

The search circuit

The world of quantum computing revolves around designing a circuit that creates an interesting superposition state, that can later be exploited to process a particular computation. One common technique to do is to create the super position where all possible states in a quantum register have equal measuring probability, this state is called the uniform superposition. For example in a 2 qubit register the uniform super position would be the state:

$$ \psi = \frac{1}{4}(|00> + |01> + |10> + |11>) $$

More generally the uniform super position of an n-qubit register is:

$$ \psi = \frac{1}{\sqrt{2^n}}\sum_{0}^{2^n-1}|x> $$

Such a circuit can be created via hadamard gates applied to each of the input qubits for a quantum register set to 0

The final circuit

By combining both parts we get the final circuit.

At the end of the circuit we apply hadamards to finalize the search circuit and read the measurement to classical bits.

sc4

The circuit is initialized with the state |0> plus an ancilla qubit set to |1> which helps us encode the oracle unitary and the uniform superposition. Notice the circuit labelled search circ is actually built for the hidden string s and it varies depending on s.

Finally when running the circuit we should expect to read back the hidden string s in the classical bits. Interestingly we only need to run this circuit one time to properly discover the string s. Recall the classical algorithm needs to iterate through each of the bits in the string s in order to discover s.

sc5

For the complete code, feel free to look at this repository which contains a runnable notebook you can play with.

Building the Q# compiler in mac os

Earlier this year Microsoft open sourced a number of their quantum programming tools including the compiler for the qsharp(q#) quantum programming language. I really enjoy reading and learning from open source software, so the news were really exciting for me since it allowed to look at the internals of qsharp.

The following post summarizes some of my experiences working and building the qsharp compiler code base as member of the open source comunity.

My main dev environment is macOS so lots of the instructions here will be targeted for it, however if your are running a *nix environment is pretty much same.

Prerequisites

Here is the list of things you are going to need to build the qsharp compiler.

  • Dotnet

    $> dotnet --version
    3.0.101
    
  • Power shell

    $> brew cask install powershell
    ...
    $> pwsh --version
    PowerShell 6.2.3
    
  • Qsharp’s source code

    $> git clone https://github.com/microsoft/qsharp-compiler.git
    
  • bsondump and jq To visualize the compiler output. I found it surprinsing that there was no easy way to install a bson->json converter so I decided to build a mongodb tool from the source above (FYI you’ll need the go tool chain for that)

  • A text editor of your choice. Here life starts getting a little complicated for macOS users. Vim, usually my editor of choice, sadly struggled to support symbolic navigation, specially cross-project. Visual Studio Code, fine choice for most projects, and an excellent choice for C# projects, did not have a good F# plugin. I settled for Visual Studio for macOS, even though it lacks some pretty key text editor plugins (vim style emulation, for example). On the plus side I found that Visual Studio offered the best experience when navigating a mix C#, F# code base.

Building

  • Move to your the qsharpcompiler repository and execute the boostraping script
$> cd qsharp-compiler
$> pwsh bootstrap.ps1
...
Enable telemetry: false
Adding Newtonsoft.Json.Bson
Adding Microsoft.VisualStudio.LanguageServer.Protocol
Adding FSharp.Core
Adding System.ValueTuple
Adding Newtonsoft.Json
Adding System.Collections.Immutable
Adding Markdig
Adding YamlDotNet
Adding FParsec
Adding Microsoft.CodeAnalysis.CSharp

dependency
----------
{dependency, dependency, dependency, dependency…}
  • Build the compiler project
$> dotnet build QsCompiler.sln
Microsoft (R) Build Engine version 16.3.2+e481bbf88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
....

Make sure you have sync’d your repo with the lastest qsharp repository. I fixed a few minor issues with the build script in macOS and they relatively new commits.

If everything worked fine, you now should be able to call the qsharp compiler from its command line tool.

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc
Microsoft Q# compiler command line tool. 1.0.0
© Microsoft Corporation. All rights reserved.

ERROR(S):
  No verb selected.

  build       Builds a compilation unit to run on the Q# quantum simulation framework.

  diagnose    Generates intermediate representations of the code to help diagnose issues.

  format      Generates formatted Q# code.

  help        Display more information on a specific command.

  version     Display version information.

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc version
Microsoft Q# compiler command line tool. 1.0.0

Running it

With a built compiler we are ready to take for a spin. The command line tool of the qsharp compiler, provides a few options to specify input. For example we can pass a snippet of q# code like so:

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -s "var uf = 2;"

Error QS3034:
File: /Users/eginez/repos/qsc/__CODE_SNIPPET__.qs
Position: [ln 1, cn 5]
Unexpected code fragment.

Error QS3035:
File: /Users/eginez/repos/qsc/__CODE_SNIPPET__.qs
Position: [ln 1, cn 1]
An expression used as a statement must be a call expression.

____________________________________________

Q# compilation failed: 2 errors, 0 warnings


$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -s "mutable uf = 2;"
____________________________________________

Q#: Success! (0 errors, 0 warnings)

Of course you probably want to save the source code to a file and pass that file to the compiler, for that you can do

$> cat sample.qs
namespace blank {
        operation OneQ () : Unit {
        using(q = Qubit()) {
        }
    }
}
$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -i sample.qs -o out/
____________________________________________

Q#: Success! (0 errors, 0 warnings)

$>ls out
twnlm5ty.bson twnlm5ty.dll

The output of the compiler is both a bson file and dll with the bson in it. Finally you can look at the output of the compiler with the bsondump tools

$> $GOPATH/mongodb/mongo-tools/bin/bsondump twnlm5ty.bson|jq
...
"Statements": [
                          {
                            "Statement": {
                              "Case": "QsQubitScope",
                              "Fields": [
                                {
                                  "Kind": {
                                    "Case": "Allocate"
                                  },
                                  "Binding": {
                                    "Kind": {
                                      "Case": "ImmutableBinding"
                                    },
                                    "Lhs": {
                                      "Case": "VariableName",
                                      "Fields": [
                                        "q"
                                      ]
                                    },
                                    "Rhs": {
                                      "Case": "SingleQubitAllocation"
                                    }
                                  },
                                  "Body": {
                                    "Statements": [],
                                    "KnownSymbols": {
                                      "Variables": [
                                        {
                                          "VariableName": "q",
                                          "Type": {
                                            "Case": "Qubit"
                                          },
                                          "InferredInformation": {
                                            "IsMutable": false,
                                            "HasLocalQuantumDependency": false
                                          },
                                          "Position": {
                                            "Case": "Value",
                                            "Fields": [
                                              {
                                                "Item1": {
                                                  "$numberInt": "1"
                                                },
                                                "Item2": {
                                                  "$numberInt": "8"
                                                }
                                              }
                                            ]
                                          },
                                          "Range": {
                                            "Item1": {
                                              "Line": {
                                                "$numberInt": "1"
                                              },
                                              "Column": {
                                                "$numberInt": "7"
                                              }
                                            },
                                            "Item2": {
                                              "Line": {
                                                "$numberInt": "1"
                                              },
                                              "Column": {
                                                "$numberInt": "8"
                                              }
                                            }
                                          }
                                        }
                                      ],
....

As you can see the compiler outputs the whole AST and metadata in json format.

The compiler code itself is split into a number of packages, some interesting packages to look at are: Optimizations, SyntaxProcessor, Compilation Manager. In addition the compiler project has a number of targets, for example: CommandLineTool, LanguageServer and the Tests targets. The CommandLineTool and the Test targets are the most relevent and as we saw built with no problems, the Test target still has a build problem on macOS I haven’t tracked down yet.