The *Register* type represents a quantum state vector, which can be viewed as analogous to a memory register. The register contains a collection of computational basis states, which represent elements that may be manipulated via gates using matrix algebra.

The register may be constructed by either specifying the number of random qubits to automatically create, or by passing in an array of qubits. Constructing a register with randomly generated qubits is guaranteed to produce a normalised state vector, constructing the register with custom generated qubits may result in the state vector not normalising correctly. The state vector should be normalised before processing any instructions (read more on normalisation).

When the register is constructed, the number of qubits governs the size of the state vector using the formula *2 ^{n}* where

The *Register* type contains much of the collection manipulation functionality that you would expect of a standard FCL collection, however due to the nature of the underlying mathematics, ad-hoc element addition and deletion is not supported. From 1.0.0.3, it is not possible to add or remove any state vector elements.

Consider the following C# code, which demonstrates various register functionality:

public static void Main(string[] Arguments) { int iQubits = 3; // Construct the register with 3 random qubits Register oRegister = new Register(iQubits); // Write qubit information to the console WriteQubits(oRegister); // Write state vector information to the console WriteStateVector(oRegister); // Ensure that the register is normalised if (oRegister.IsNormalised() == false) { Console.WriteLine(); Console.WriteLine("Normalising the state vector..."); oRegister.Normalise(); // Write the updated information to the console WriteStateVector(oRegister); Console.WriteLine(); } // Perform a Z measurement on qubit 1 string sBasis = "Z"; int iQubitToMeasure = 1; // The measure result value will be either a 0 or a 1 int iMeasurementResult = oRegister.Measure(sBasis, iQubitToMeasure); Console.WriteLine(); Console.WriteLine("{0} measurement of qubit {1} result was: {2}", sBasis, iQubitToMeasure, iMeasurementResult); // Write out the final state WriteQubits(oRegister); WriteStateVector(oRegister); } private static void WriteQubits(Register Register) { Console.WriteLine(); Console.WriteLine("Qubits:"); for (int i = 0; i < Register.Qubits.Count; i++) { Console.Write("({0}|0> + {1}|1>)", Register.Qubits[i].AlphaLabel, Register.Qubits[i].BetaLabel); if (i < (Register.Qubits.Count - 1)) { Console.Write(" (x) "); } } Console.WriteLine(); } private static void WriteStateVector(Register Register) { Console.WriteLine(); Console.WriteLine("State Vector:"); Console.Write("|v> = ("); for (int i = 0; i < Register.StateVector.Length; i++) { // Using the overload to control the output Console.Write(Register.StateVector[i].ToString(true, true)); if (i < (Register.StateVector.Length - 1)) { Console.Write(" + "); } } Console.WriteLine(")"); }

And again, this time in F#:

type Program() = [<EntryPoint>] static let main argv = let iQubits = 3 // Construct a register, prepared with 3 random qubits let oRegister = new Register(iQubits) // Write qubit information to the console Program.WriteQubits(oRegister) // Write the state vector to the console Program.WriteStateVector(oRegister) // Ensure the register is normalised // A register prepared with random qubits is guaranteed to be normalised if oRegister.IsNormalised() = false then printfn "" printfn "Normalising the state vector..." oRegister.Normalise() // Write the updated information to the console Program.WriteStateVector(oRegister); printfn "" // Perform a Z measurement on qubit 1 let sBasis = "Z"; let iQubitToMeasure = 1; // The measure result value will be either a 0 or a 1 let iMeasurementResult = oRegister.Measure(sBasis, iQubitToMeasure) printfn "" printfn "%s measurement of qubit %d result was: %d" sBasis iQubitToMeasure iMeasurementResult // Write out the final state Program.WriteQubits(oRegister) Program.WriteStateVector(oRegister) 0 // return an integer exit code static member WriteQubits(register: Register) = printfn "" printfn "Qubits:" for i in 0 .. (register.Qubits.Length - 1) do let oQubit = register.Qubits.[i] printf "(%s|0> + %s|1>)" oQubit.AlphaLabel oQubit.BetaLabel if i < (register.Qubits.Length - 1) then printf " (x) " printfn "" static member WriteStateVector(register: Register) = printfn "" printfn "State Vector:" printf "|v> = (" for i in 0 .. (register.StateVector.Length - 1) do // Using the overload to control the output let sState = register.StateVector.[i].ToString(true, true) printf "%s" sState if i < (register.StateVector.Length - 1) then printf " + " printfn ")"

This small program produces output similar to:

Qubits: (A|0› + B|1›) (x) (C|0› + D|1›) (x) (E|0› + F|1›) State Vector: |v› = (0.012 ACE|000› + 0.164 ACF|001› + 0.053 ADE|010› + 0.721 ADF|011› + 0.011 BCE|100› + 0.148 BCF|101› + 0.048 BDE|110› + 0.652 BDF|111›)

Note that here both the coefficient and the algebraic values have been written to the console. At this point in the program, the coefficient is indeed a product of its constituent terms, however as soon as manipulation takes place, this property may no longer valid. At this time, you should consider the algebraic value as simply a way of tracking how a value is moved through the system.

A better way to view these elements is with either the coefficient or the algebraic values displayed:

State Vector: // Algebraic values only |v› = ( ACE|000› + ACF|001› + ADE|010› + ADF|011› + BCE|100› + BCF|101› + BDE|110› + BDF|111›) // Coefficients only |v› = (0.012|000› + 0.164|001› + 0.053|010› + 0.721|011› + 0.011|100› + 0.148|101› + 0.048|110› + 0.652|111›)

The important thing to remember from this output above is that *ACE = 0.012* (etc.) is only a property of the state vector when it is first prepared.

Z measurement of qubit 1 result was: 1 Qubits: (A|0› + B|1›) (x) (C|0› + D|1›) (x) (E|0› + F|1›) State Vector: |v› = ( ACE|000› + ACF|001› + 0.054 ADE|010› + 0.740 ADF|011› + BCE|100› + BCF|101› + 0.049 BDE|110› + 0.669 BDF|111›)

It may not be obvious at first just how 3 qubits turn into 8 computational basis states, however looking closer at the qubit and state vector definitions should help.

The computational basis state ACE|000› is a superposition of A|0›, C|0›, and E|0›. In a similar fashion, the computational basis state BCF|101› is a superposition of B|1›, C|0›, and F|1›. You could actually ignore the algebraic values out the front of the computational basis state completely such that |000› is a superposition of |0›, |0›, and |0›. In a similar fashion, the computational basis state |101› is a superposition of |1›, |0›, and |1›. There will always be some kind of coefficient value however, so it would be more correct to write these values as α|000› or β|101›.

The algebraic value ACE suggests that the coefficient of the |000› qubit is derived as a product of (A|0› * C|0› * E|0›), and it is - at least when the register is initially created, these values are guaranteed to be a mathematical product derived from their constituent parts. Once manipulation of the state vector commences, it may be no longer possible to decompose a coefficient value back to its constituent terms. At this point, the algebraic value should be considered a label useful for only for tracking computations.

Copyright © 2018 carlbelle.com