Friday, July 9, 2010

Testing and More Testing

Last week, I wrote about how I was working to make my code create matrix representations of arbitrary gates. This week was a little bit slower and mostly involved writing tests to ensure that my code was really working.

There were a few minor changes that I ended up having to make so that everything would work for arbitrary 3-qbit gates. To check my sanity, I followed through an example in "Quantum Computation and Quantum Information" by Nielsen and Chuang and saw if my results matched theirs. This example had a set of single and 2-qbit gates that formed a quantum Fourier transform on a three qbit system, they also showed the matrix that would represent this transformation. Thus, this was a good way to make sure everything in my apply and represent functions was consistent with the text. After realizing that I was reading the circuit diagram upside down and backwards, I was able to confirm that my code produced the same results as the book. I repeated this for a few other select examples and came to a similar conclusion.

All in all, I am making good progress towards simulating a quantum computer.

Thursday, July 1, 2010

Multi-Qbit Gates and Gate Simplification

One of the greatest things about Sympy is its ability to maintain symbolic representations of items inside Mul, Pow, and Add classes. This makes symbolic manipulations possible before ever doing any calculations. This week, I started developing gate simplification code.

The first step in the gate simplification process is sorting the gates, which cannot be done using Mul's built in sorting functions as the commutativity rules for gates is not as simple as 'does' or 'does-not' commute. Gates commute with other gates that do not act on the same qbit; in addition, the ZGate, pi/8-Gate and phase gate always commute with themselves. I chose to use a bubble-sort to do the sorting as it was very easy to ensure a bubble-sort doesn't incorrectly exchange elements; it would be much harder to have a merge-sort or other NLogN algorithm do this.

Once the gates are sorted, keeping in mind special commutation relations, the code can then preform gate simplifications. The Hadamard, X, Z, and Y gates all produce Unity when squared. The pi/8-Gate produces the phase-Gate when squared, and the phase-Gate squared produces a Z-Gate. I have implemented these very simplistic rules.

Another thing I did this week was implement intrinsically multi-qbit gates. Before explaining how this works, I'll need to get some nomenclature out of the way. For multi-qbit gates, the first bits it acts on are called the control bits with the last bit representing the target bit. To start, I first generalized the apply method so that it could take in a square powered of 2 sized matrix and apply it to any given state. Thus:

In [8]: apply_gates(CNOTGate(0,1)*(x*Qbit(0,0) + y*Qbit(0,1) + z*Qbit(1,0) + w*Qbit(1,1)))
Out[8]: w⋅|01> + x⋅|00> + y⋅|11> + z⋅|10>
#This is as we would expect as it chose to flip the first bit contingent on the 0th bit being True

To prove to myself that the code was actually working, I created an arbitrary 4x4 matrix with symbols for each element that are in alphabetical order. I then applied the gate to Qbits with the control and target set to all 4 of their permutations and several 'junk' bits that should not change the result of the output. By hand, I figured out how the state should change. Here is one of the four inputs that I put in:

In [14]: apply_gates(Arb(2,0)*(Qbit(0,1,0)))
Out[15]: a⋅|010> + e⋅|011> + i⋅|110> + m⋅|111>


After doing this, I also checked the 8 possible unique inputs for an arbitrary 8x8 matrix.

The step of representing these gates as matrices acting in arbitrary Hilbert spaces was non-trivial as it is not generally possible to express the matrix as the tensor product of several unities with the matrix in the special 2 qbit case. Fortunately, this article had an example of how several different multi-qbit gates could be expressed in Dirac Notation starting at page 35. With the help of Dr. Gutierrez, I was able to determine a general method for expressing a multi-qbit gate acting on any number of qbit(s).

After coding this method in, I tested the code exhaustively by making an arbitrary 4x4 and 8x8 gate matrix and saw if my apply method (which I am fairly confident works) agrees with my matrix-represent method. After changing some small mix-up's with Endian-ness, I found that the two functions agreed as to the results of applying the gates.

I added many more tests to my code this week, but I clearly need more to make sure that everything actually works. Also, I still need to develop basis transformations for states and gates.

Friday, June 25, 2010

More On Operations

I added some more functionality to the code this week.

I gave the code the ability to build single qbit gates that work in multi-Qbit settings.
In order to do this, I had to take the matrix-representation of the gate operating on a single Qbit and take the tensor product of it with Unities; these Unities belong in the place of the qbits that are unaffected by the gate. Thus, a Hadamard Gate on the 1st bit in a 4-qbit setting is the tensor product (I x I x H x I), where I is a 2x2 unity matrix and H is the Hadamard Matrix.

For this to work, I would have to implement a Kronecker (Tensor) Product for matrices. The Kronecker Product function that I created does the Kronecker Product for an arbitrary number of input matrices of arbitrary size. I also produced test files that tested the Product against the Kronecker product that already exists in a Python library called Numpy. With this product working, I was able to make the single qbit gates act on any number of qbits.

Dr. Granger told me to implement an apply method which would be able to apply the gates to any number of qbits without doing a full matrix representation using Tensor Products. To do this, I used Qbit objects to represent a single state inside a ket with a probability amplitude multiplying. This works like this:

In [7]: circuit = HadamardGate(0)*XGate(1)*Qbit(0,0,0,0,0)

In [8]: print circuit
Out [8]: H(0)*X(1)*|00000>

In [9]: apply_gates(circuit)
Out[9]: 2**(1/2)/2*|00010> + 2**(1/2)/2*|00011>

This output is clearly much cleaner than the output given by the represent() function, which prints a long matrix. Having an output with states inside kets multiplied by their respective probability amplitude makes quite a bit more sense than a long column matrix. As such, I taught the code to take the matrix representation and turn it into this format using the matrix_to_qbits function.

The ability to switch the matrix representation into an expression in Dirac Notation allowed me to test to see if the apply and represent functions produced the same results. The testing stage of my code is far from complete so I need to continue debugging and creating tests in my test file. Also, I plan on creating a simpgate() function that will rearrange gates so gates that operate on the same qbit are grouped together (gates that operate on different Qbits commute; if they operate on the same qbit, they do not) and then make any obvious simplifications.

Friday, June 18, 2010

First Week of Coding

This week, I split my time between learning more about Quantum Computation and actual coding for my project.

So far, I have taught my code how to create a single Qbit of definite state and build the single Qbit gates that are to operate on it. I have built into the gate classes the ability to represent themselves in different bases (right now I have only implemented the |0> |1> and |+> |-> bases). To see how this all works, let me show an example of me creating an XGate operating on a single Qbit of definite state |1> and then representing it in the |0> |1> basis:

In [2]: circuit = XGate(0)*Qbit(1)

In [3]: circuit
Out[3]: X(0)⋅|1>

In [5]: represent(circuit, ZBasisSet())
[1.0]
[ 0]

This is exactly what we would expect as the XGate acts in the same way as a classical NOT gate would, switching the Qbit from the state |0> to the state |1>. We can of course make the number of gates we apply more complicated, with a Gate having an X, Hadamard and Z gate applied to it in that order:

In [7]: circuit = ZGate(0)*HadamardGate(0)*XGate(0)*Qbit(1)

In [8]: circuit
Out[8]: Z(0)⋅H(0)⋅X(0)⋅|1>

In [9]: represent(circuit, ZBasisSet())
[ 0.707106781186547]
[-0.707106781186547]

A quick matrix multiplication confirms that this is the expected result.

In the future, I will want to make the 'represent' function output in the standard |ket> notation. Also, I will need to implement a simplify function which will make any obvious simplifications to the gates. To generalize these gates so they can operate on multiple Qbits, the code will need to take the Kronecker Product of the 2x2 matrix with several unity matrices. Also, I will want to create tests to automatically test the code.

Much of this week I spent reading through relevant resources. I thoroughly read the first chapter of Mermin's book "Quantum Computer Science: An Introduction". This book introduces Quantum Computation by first discussing reversible classical gates (some not all that useful) and then generalizes these gates to quantum computation; the book goes through quite a few gate equivalences that I will want to teach the code to recognize.

I also started digging through a article describing the Solovay-Kitaev algorithm which allows an arbitrary single qbit operator to efficiently be approximated in terms of our set of universal gates; I will want to teach my code how to do this.

Friday, June 11, 2010

Plans

I just turned in my last take home final today and am ready to begin work on my GSoC project.

Over the summer, I plan to implement qubits and gates as objects, which will be contained within a Mul object that shows how and when to apply gate operations. Together, this Mul object will represent a quantum circuit operating on a set number of qubits; thus, a Mul object containing these gates will represent some quantum transformation, such as a Fourier Transform. In order to carry this out, each gate will have to keep track of which qubit(s) it will operate on.

The first step towards this general goal is the implementation of single qubit gates and the single qubit. This single qubit will need to be viewable in any observational basis. It is here that I will start my work.

I still have quite a few details to hammer out, but I look forward to starting this!

Friday, June 4, 2010

No Time for Title

This week is dead week at Poly, so I didn't get much time to work or think about my project.

Matt Curry (who has a GSoC project involving the creation of a general quantum mechanical framework in Sympy) and I did get an opportunity to discuss with Dr. Granger how our projects would fit together. Matt will design code that will keep track of the Hilbert space in which a quantum state lives. This may be of some use to my project as an n-qubit system lives in a Hilbert space which is the direct product of n l2(2) Hilbert spaces. His work will also allow states to be added, multiplied by scalers and negated--This will also be useful and will be a great addition to code that I do. I'm starting to gain respect for how object orientation makes code reuse easy.

Anyway, my last final is this Wednesday, so I should be able to start really working on my project soon!

Friday, May 28, 2010

Beginning of GSOC

The Google Summer of Code began this week; I will be blogging each week for its duration.

This week has been busy. The quantum mechanics class I have been taking has focused on exploring the uses of the bra and ket notation. We have used this notation to generalize changes from various observational bases in both finite and continuous cases. Of special importance to my project, we looked at the transformations of a two state system.

Under the advisement of Dr Granger, Matt Curry (a fellow GSoC student) and I have spent some time looking at the Sympy code while trying to mimic some of its functionality in our own code. This has helped us learn about some of the neat Python tricks Sympy has used to function. For example, Sympy uses Python operator methods (such as __mul__ or __add__) to convert mathematical expressions involving objects into complicated symbolic expression objects. This has led us to notice functions such as Simpify which convert Python number objects into specialized Sympy objects--This allows the rewriting of many methods within the class. Writing code that functions similar to Sympy's has helped me get a better understanding of how it all works.

Overall, I'm very excited to begin work on coding for the Sympy project.