QSharp: PauliZGate

04 Jun 2015

C#, F#, Maths, QSharp, Quantum Computing


The quantum Z gate is represented by the Pauli-Z matrix. It can be used to perform Z operations on a single qubit.

In QSharp, the Z gate implementation is provided by the PauliZGate type. Like all QSharp gate implementations, this type inherits from the Matrix type, which describes a mathematical matrix structure used in all gate operations. The mathematics of the PauliZGate are discussed further in the Z command documentation.

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


public static void Main(string[] Arguments) 
{ 
    //  Construct a register with 2 random qubits
    Register oRegister = new Register(2); 

    //  Always check that we start off with a valid register
    if (oRegister.IsNormalised() == false) 
    { 
        oRegister.Normalise(); 
    } 

    //  Write the initial state to the console
    WriteQubits(oRegister); 
    WriteStateVector(oRegister); 
    Console.WriteLine(); 

    //  Construct a new Pauli Z gate
    PauliZGate oPauliZGate = new PauliZGate(); 

    //  What does the Pauli Z gate look like?
    Console.WriteLine("Pauli Z:"); 
    Console.WriteLine(oPauliZGate); 

    //  Apply the gate to qubit 0
    Console.WriteLine(); 
    Console.WriteLine("Z(0);"); 
    oRegister.StateVector = oPauliZGate.ApplyTo(oRegister); 

    //  Write the state to the console
    WriteStateVector(oRegister); 

    //  Apply the gate to qubit 0 - note that this is a reversible operation
    Console.WriteLine(); 
    Console.WriteLine("Z(0);"); 
    oRegister.StateVector = oPauliZGate.ApplyTo(oRegister); 

    //  Write the state to the console
    WriteStateVector(oRegister); 

    //  Now apply the gate to qubit 1 (this is also reversible operation)
    Console.WriteLine(); 
    Console.WriteLine("Z(1);"); 
    oRegister.StateVector = oPauliZGate.ApplyTo(1, 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++) 
    { 
        //  Use the overload to control the output
        Console.Write(Register.StateVector[i].ToString(true, false)); 

        if (i < (Register.StateVector.Length - 1)) 
        { 
            Console.Write(" + "); 
        } 
    } 

    Console.WriteLine(")"); 
} 

And again, this time in F#:


type Program() = 

    [<EntryPoint>] 
    static let main argv =  

        //  Construct a register with 2 random qubits
        let oRegister = new Register(2) 

        //  Always check that we start off with a valid register
        if oRegister.IsNormalised() = false then 
            oRegister.Normalise() 

        //  Write the initial state to the console
        Program.WriteQubits(oRegister) 
        Program.WriteStateVector(oRegister) 
        printfn "" 

        //  Construct a new Pauli Z gate
        let oPauliZGate = new PauliZGate();  

        //  What does the Pauli Z gate look like?
        let sPauliZ = oPauliZGate.ToString() 
        printfn "Pauli Z:" 
        printfn "%s" sPauliZ 

        //  Apply the gate to qubit 0
        printfn "" 
        printfn "Z(0);"  
        oRegister.StateVector <- oPauliZGate.ApplyTo(oRegister);  

        //  Write the state to the console
        Program.WriteStateVector(oRegister);  

        //  Apply the gate to qubit 0 - note that this is a reversible operation
        printfn "" 
        printfn "Z(0);"  
        oRegister.StateVector <- oPauliZGate.ApplyTo(oRegister);  

        //  Write the state to the console
        Program.WriteStateVector(oRegister);  

        //  Now apply the gate to qubit 1 (this is also reversible operation)
        printfn "" 
        printfn "Z(1);"  
        oRegister.StateVector <- oPauliZGate.ApplyTo(1, 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 ")" 

In QSharp, the PauliZGate can only really do one thing: be applied to a state vector.

This small program produces the following output:

State Vector:
|v> = (AC|00> + AD|01> + BC|10> + BD|11>)

Pauli Z:
{
{1, 0},
{0,-1}
}

Z(0);

State Vector:
|v> = (AC|00> + AD|01> + -BC|10> + -BD|11>)    //  The qubits in position 0 have been multiplied by 1 and -1 (A mapped to (1 * A) = A, B mapped to (-1 * B) = -B)

Z(0);

State Vector:
|v> = (AC|00> + AD|01> + BC|10> + BD|11>)    //  The qubits in position 0 have been multiplied by 1 and -1 (A mapped to (1 * A) = A, -B mapped to (-1 * -B) = B)

Z(1);

State Vector:
|v> = (AC|00> + -AD|01> + BC|10> + -BD|11>)//  The qubits in position 1 have been multiplied by 1 and -1 (D mapped to (-1 * D) = -D, C mapped to (1 * C) = C)

* Note that coefficient values have not been written back to the console in this example

Here's the same code, however now coefficients are displayed in the console rather than algebraic values:

Qubits:
(A|0> + B|1>) (x) (C|0> + D|1>)

State Vector:
|v> = (0.903|00> + 0.378|01> + 0.187|10> + 0.078|11>)

Pauli Z:
{
{1, 0},
{0,-1}
}

Z(0);

State Vector:
|v> = (0.903|00> + 0.378|01> + -0.187|10> + -0.078|11>)

Z(0);

State Vector:
|v> = (0.903|00> + 0.378|01> + 0.187|10> + 0.078|11>)

Z(1);

State Vector:
|v> = (0.903|00> + -0.378|01> + 0.187|10> + -0.078|11>)

In this example, it may be easier to focus just on the single coefficient, rather than tracking two algebraic values per state vector element.


 

Copyright © 2024 carlbelle.com