StationQ / Liquid

The Language-Integrated Quantum Operations (LIQUi|>) Simulator
http://StationQ.github.io/Liquid
Other
440 stars 97 forks source link

n-Controlled Gate with 0 and 1 states #44

Closed EnginSahinCE closed 7 years ago

EnginSahinCE commented 7 years ago

I want to make a controleld gate but source qubits are not only 1 state, for example C-Swap (n qubit controlled);

let consider that we have |phi> state; qs: |0001> -> H [qs.[1]]; H [qs.[2]]; -> |0001>+|0011>+|0101>+|0111> = |phi>

and apply SWAP(0,3) gate with controlled |10> for controlled qubits 1,2; (if qubit[1]=1 and qubit[2]=0 then apply SWAP(q.[0];q.[3]) gate); U |phi> -> |0001>+|0011>+|1100>+|0111>

(or controlled |1010> for controlled qubits 1,2,3,4) Can i do this, how do i ?

dbwz8 commented 7 years ago

There are several ways to do this. The easiest is to create a new gate with the exact Unitary matrix of the multi-controlled gate you want. For example, Toffoli is done with:

/// <summary>
/// Performs a Toffoli or Controlled-Controlled-NOT gate
/// </summary>
/// <param name="qs">The first two qubits in the list are the control qubits, and the third qubit is the target,</param>
let CCNOT (qs:Qubits) =
    let gate =
        Gate.Build("CCNOT",fun () ->
            new Gate(
                Name    = "CCNOT",
                Help    = "Toffoli - Controlled Controlled Not",
                Mat     = (
                    let m       = CSMat(8)
                    m.r(6,6)   <- 0.0
                    m.r(6,7)   <- 1.0
                    m.r(7,7)   <- 0.0
                    m.r(7,6)   <- 1.0
                    m),
                Draw    = "\\ctrl{#1}\\go[#1]\\ctrl{#2}\\go[#2]\\targ"
        ))
    gate.Run qs

Another way is to use the Cgate (or CCgate) gate that adds a control to an existing gate (or one you've already defined):

/// <summary>
/// Performs a parent gate under two-qubit quantum control.
/// The parent must be a unitary gate.
/// </summary>
/// <param name="f">The gate to control.</param>
/// <param name="qs">The first two qubits are the control, and the remainder are passed to the parent gate.</param>
let CCgate (f:Qubits->unit) (qs:Qubits) =
    let gate (f:Qubits->unit) (qs:Qubits) =
        let parent      = !< f qs.Tail.Tail
        parent.AddControl(2)
    (gate f qs).Run qs

Notice the use of AddControl which will add any number of controls to another gate (the parent).

Now comes the question of how to do "0" controlled gates. Just create the gate (by either method above) with "1" controls and then create a wrapper gate with an "X" before (and after) the control gate on each line you want controlled with a "0". Here's a sample wrapper gate from inside the Shor algorithm:

/// <summary>
/// Controlled rotation gate
/// </summary>
/// <param name="k">Rotation by 2^k</param>
/// <param name="qs">Qubits ([0]=Control [1]=rotated)</param>
let CR (k:int) (qs:Qubits) =
    let gate (k:int) (qs:Qubits)    =
        Gate.Build("CR_" + k.ToString() ,fun () ->
            new Gate(
                Qubits  = qs.Length,
                Name    = "CR",
                Help    = "Controlled R gate",
                Draw    = sprintf "\\ctrl{#1}\\go[#1]\\gate{R%d}" k,
                Op      = WrapOp (fun (qs:Qubits) -> Cgate (R k) qs)
        ))
    (gate k qs).Run qs

In the WrapOp function you can put as many X gates as you like. This should give you everything you need to create your new gate.

EnginSahinCE commented 7 years ago

thank you for your help. I could not think of the X gate before Cgate(and after).

dbwz8 commented 7 years ago

I think you misunderstood what I meant. The X gates go outside of the control gate. For example, change your code to this:

        let CG (f:Qubits->unit) (qs:Qubits) =
            let gate (f:Qubits->unit) (qs:Qubits) =
                let parent = !< f qs.Tail.Tail
                parent.AddControl(2)                
            (gate f qs).Run qs

        let C0C0X  (qs:Qubits) =
            let gate  (qs:Qubits)    =        
                Gate.Build("C0C0_X"  ,fun () ->
                    new Gate(
                        Qubits  = qs.Length,
                        Name    = "CX",
                        Help    = "Controlled_0 Controlled_0 X gate",
                        Draw    = sprintf "\\ctrlo{#1}\\go[#1]\\ctrlo{#2}\\go[#2]\\gate{X}",
                        Op      = WrapOp (fun (qs:Qubits) -> 
                                    X >< !!(qs,[0;1])
                                    CG X qs
                                    X >< !!(qs,[0;1])
                                    )
                ))
            (gate qs).Run qs

        let k = Ket(4)
        let qs = k.Qubits
        H >< !!(qs,1,2)
        let _   = k.Single()
        k.Dump showInd
        C0C0X !!(qs,0,2,3)
        k.Dump showInd

and what you get for output is:

0:0000.0/Ket of 4 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0 1 2 3
0:0000.0/0x00000000: 0.5
0:0000.0/0x00000002: 0.5
0:0000.0/0x00000004: 0.5
0:0000.0/0x00000006: 0.5
0:0000.0/Ket of 4 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0 1 2 3
0:0000.0/0x00000001: 0.5
0:0000.0/0x00000002: 0.5
0:0000.0/0x00000005: 0.5
0:0000.0/0x00000006: 0.5

which I believe is what you wanted.

EnginSahinCE commented 7 years ago

After I wrote what you wanted to say, I understood and I deleted the other question. I first noticed X then X event later. Thank you so much for your help again. My problem is solved.