StationQ / Liquid

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

Behaviour Entanglement #60

Closed mtiepelt closed 6 years ago

mtiepelt commented 6 years ago

Hello all,

[you may jump this and look at the below example] I recently started to work with Liquid and got some "issues" when trying to implement control operations on gates/ operations of arbitrary size (e.g. QFT, AdditionGate, ...), since I can not give explicit matrix representations for those.

My current workaround is to have nested Cgate(Cgate ... CGate(R qs)... ))) (e.g. for QFT, QFT based addition. For example for a modular multiplication I need at least 3 nestes controls for the QFT in the QFT based addition... As this get overly complicated I tried to use ancillary Qubits and Toffoli gates to circumvent the nesting. When trying to uncompute the ancillary Qubits however, they seem to stay entangled.

It seems that the application of two subsequent CNOT gates also does not uncompute the entanglement, at least when trusting the "Entangled" property of the Qubits. Below is a minimal working example and the output.

If I am doing something fundamentally wrong with Liquid and this is circumvented on proper usage, I would be grateful to get a hint! Or perhaps, any way to define controls on arbitrary gates/ operations?

Thanks in advance, kind regards, Marcel

PS: Also, the mailing list is not existent anymore?

EDIT: As the entanglement and un-computation does seem to work in general, perhaps the ".Entangled" property is just an internal state thats set after the first entanglement; but Liquid can not distinguish between un-computation and un-entanglement and further operations on qubits?

Minimal Working Example: let ket = Ket(2) let qs = ket.Qubits

    // Should not be entangled
    show "Should not be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled
    CNOT !!(qs.[0],qs.[1])          // [qs.[0];qs.[1]] results in same output

    // Should be entangled
    show "Should be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled

    CNOT !!(qs.[0],qs.[1])
    // Should not be entangled
    show "Should not be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled

Output: 0:0000.0/=============== Logging to: Liquid.log opened ================ 0:0000.0/ 0:0000.0/ Secs/Op S/Qubit Mem(GB) Operation 0:0000.0/ ------- ------- ------- --------- 0:0000.0/Should not be entangled 0:0000.0/ ENT? false 0:0000.0/ ENT? false 0:0000.0/Should be entangled 0:0000.0/ ENT? true 0:0000.0/ ENT? true 0:0000.0/Should not be entangled 0:0000.0/ ENT? true 0:0000.0/ ENT? true

dbwz8 commented 6 years ago

I'm currently traveling in Europe but will get to this by next week (sorry for the delay).

dbwz8 commented 6 years ago

[sorry for the delay... up to my backside in aligators at the moment ;]

Your guess at what "Entangled" means is correct. Let me slightly add to your example:

    let ket = Ket(2)
    let qs = ket.Qubits

    H !!(qs,0)

    // Should not be entangled
    show "Should not be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled
    CNOT !!(qs,0,1)          // [qs.[0];qs.[1]] results in same output

    // Should be entangled
    show "Should be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled

    show "====================================================="
    show "Result after first CNOT:"
    ket.Dump showInd    
    show "====================================================="

    CNOT !!(qs,0,1)

    // Should not be entangled
    show "Should not be entangled"
    show "<qs0> ENT? %b" qs.[0].Entangled
    show "<qs1> ENT? %b" qs.[1].Entangled

    show "====================================================="
    show "Result after second CNOT:"
    ket.Dump showInd    
    show "====================================================="

    let kets    = ket.Split([!!(qs,0);!!(qs,1)],true)

    show "====================================================="
    show "Result after ket split:"
    kets.[0].Dump showInd
    kets.[1].Dump showInd
    show "====================================================="

    show "Should REALLY not be entangled"
    show "<qs0> ENT? %b" kets.[0].Qubits.[0].Entangled
    show "<qs1> ENT? %b" kets.[1].Qubits.[0].Entangled

    show "DONE"

Things I added:

When you run this, you'll get:

0:0000.0/Should not be entangled
0:0000.0/<qs0> ENT? false
0:0000.0/<qs1> ENT? false
0:0000.0/Should be entangled
0:0000.0/<qs0> ENT? true
0:0000.0/<qs1> ENT? true
0:0000.0/=====================================================
0:0000.0/Result after first CNOT:
0:0000.0/Ket of 2 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0 1
0:0000.0/0x00000000: 0.7071
0:0000.0/0x00000003: 0.7071
0:0000.0/=====================================================
0:0000.0/Should not be entangled
0:0000.0/<qs0> ENT? true
0:0000.0/<qs1> ENT? true
0:0000.0/=====================================================
0:0000.0/Result after second CNOT:
0:0000.0/Ket of 2 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0 1
0:0000.0/0x00000000: 0.7071
0:0000.0/0x00000002: 0.7071
0:0000.0/=====================================================
0:0000.0/=====================================================
0:0000.0/Result after ket split:
0:0000.0/Ket of 1 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0
0:0000.0/0x00000000: 0.7071
0:0000.0/0x00000001: 0.7071
0:0000.0/Ket of 1 qubits:
0:0000.0/=== KetPart[ 0]:
0:0000.0/Qubits (High to Low): 0
0:0000.0/0x00000000: 1
0:0000.0/=====================================================
0:0000.0/Should REALLY not be entangled
0:0000.0/<qs0> ENT? false
0:0000.0/<qs1> ENT? false
0:0000.0/DONE

You are correct, all the .Entangled does is check that the qubit was ever in an operation that might have entangled it. The only way to really check for entanglement is to Split the Ket vector with the second argument asking to check if this was really legal. What happens is that Liquid creates the desired product state, then puts it back together and sees if it matches the original Ket vector (VERY expensive, so we don't do it unless you really want it).

If you look at the dumps, you'll see that the state vector is correct at all points... just that the system really has no way to know what might have become unentangled as the result of your circuit.

dbwz8 commented 6 years ago

Please re-open if this wasn't clear/what you needed.

mtiepelt commented 6 years ago

Great thanks!