Measure in arbitrary bases - how to find quantum gates

I have a qubit |ψ⟩ and I want it to measure in bell states. My procedure is now
to calculate the transformation matrix U=Σ|i⟩⟨b_i| where |i⟩ is the computation basis and ⟨b_i| are the bell states. It works so far. The code in Yao.jl

function getFreq(r, shots, state_nr)
    statistics = zeros(Int64, state_nr)
    for i in eachindex(r) statistics[r[i].buf + 1] +=  1 end
    statistics/shots
end

# we define Σ|i⟩⟨b_i| where b_i is bell state
function defOperator()
    ϕ⁺ =  Array(1/sqrt(2)*[1.0+0.0im,0,0,1])
    ϕ⁻ =  Array(1/sqrt(2)*[1.0+0.0im,0,0,-1])
    Ψ⁺ =  Array(1/sqrt(2)*[0,1.0+0.0im,1,0])
    Ψ⁻ =  Array(1/sqrt(2)*[0,1.0+0.0im,-1,0]) 
    return reshape([ϕ⁺;ϕ⁻;Ψ⁺;Ψ⁻],(4,4))'
end

op = defOperator()
ψ=ComplexF64[4.0, 2.0im,1.0,-2.0im]  
Yao.normalize!(ψ)
qubit = Yao.ArrayReg(ψ) 
block=GeneralMatrixBlock(op)
circuit = chain(2, block)
results = measure(apply(qubit, circuit), nshots=1000)
# |⟨Φ⁺,ψ⟩|^2=0.4   |⟨Φ⁻,ψ⟩|^2=0.4   |⟨Ψ⁺,ψ⟩|^2=0.1  |⟨Ψ⁻,ψ⟩|^2=0.1
getFreq(results,1000,4)

output:

 0.392
 0.401
 0.098
 0.109

How can I achieve the same goal with quantum gates CNOT and other gates(X,Y,Z,H,…)?
Is there no simple way to decompose the unitary matrix in quantum gates?

After some searching the net(if somebody has the same problem):
I believe in this special case (bell bases) - we know how to create them:

ctrl_reg = control(1, 2=>X)
bellcircuit = chain(2, put(1 => H), ctrl_reg)

we can construct the inverse: CNOT and Hadamard are their own inverse, so
the inverse transformation is

reverse_bell_circuit=chain(2, ctrl_reg, put(1 => H))

so we can substitute the transform matrix by the gates above:

op = defOperator()
ψ=ComplexF64[4.0, 2.0im,1.0,-2.0im]  
Yao.normalize!(ψ)
qubit = Yao.ArrayReg(ψ) 
block=GeneralMatrixBlock(op)
circuit = chain(2, block)
results = measure(apply(qubit, circuit), nshots=1000)
# |⟨Φ⁺,ψ⟩|^2=0.4   |⟨Φ⁻,ψ⟩|^2=0.4   |⟨Ψ⁺,ψ⟩|^2=0.1  |⟨Ψ⁻,ψ⟩|^2=0.1
println("frequency:  ",getFreq(results,1000,4))
reverse_bell_circuit=chain(2, control(1, 2=>X), put(1 => H))
results = measure(apply(qubit, reverse_bell_circuit), nshots=1000)
println("frequency:  ",getFreq(results,1000,4))

Results:

frequency:  [0.386, 0.417, 0.099, 0.098]
frequency:  [0.393, 0.394, 0.105, 0.108]

My conclusion:
But if you have no idea how the NOT standard basis is created you have to use one of the complicated algorithm of decomposition of unitary matrix into quantum gates!
Please tell me if you know a better idea!

1 Like

Interesting using case. Actually, you can measure an operator directly in Yao.

using Yao

function bell_operator()
    z = zero_state(1)
    o = zero_state(1) |> X
    return projector((join(z,z) + join(o,o)) / sqrt(2)) +
        2 * projector((join(z,z) - join(o,o)) / sqrt(2)) +
        3 * projector((join(z,o) + join(o,z)) / sqrt(2)) +
        4 * projector((join(z,o) - join(o,z)) / sqrt(2))
end

qubit = ArrayReg(Yao.normalize!([4.0, 2.0im,1.0,-2.0im]))
results = measure(bell_operator(), qubit, nshots=1000)
# |⟨Φ⁺,ψ⟩|^2=0.4   |⟨Φ⁻,ψ⟩|^2=0.4   |⟨Ψ⁺,ψ⟩|^2=0.1  |⟨Ψ⁻,ψ⟩|^2=0.1
map(k->count(i -> i ≈ k, results)/length(results), 1:4)

To create the dagger of an operator, you can use ' in Yao:

julia> bellcircuit = chain(2, put(1 => H), control(1, 2=>X))
nqubits: 2
chain
├─ put on (1)
│  └─ H
└─ control(1)
   └─ (2,) X


julia> reverse_bell_circuit = bellcircuit'
nqubits: 2
chain
├─ control(1)
│  └─ (2,) X
└─ put on (1)
   └─ H
1 Like

@1115
Interesting shortcuts - I did not know that (measuring a unitary matrix)!
So measuring in Yao seems no problem - building the hardware for this operator(decomposing it in gates) - the problem exists further I believe!
Thank you anyway - I have again learned something

You are right. Just to clarify, the bell_operator that I defined is not a unitary operator. It is Hermitian. I am not sure if a unitary operator can be measured.