Define quantum noise channel

Hi, guys

I am trying to define the amplitude damping channel in ITensor. Basically I want to have two single site operators K_0 = \begin{pmatrix} 1 &0\\ 0 & \sqrt{1-\gamma}\end{pmatrix} and K_1 = \begin{pmatrix} 0& \sqrt{\gamma}\\0&0\end{pmatrix} on each site. Thus my density operator under the amplitude damping channel looks like K_0\rho K_0^{\dagger}+K_1\rho K_1^{\dagger}. How to define the gates K_0 and K_1 with parameter \gamma. I tried


import  ITensors :op
using ITensors
function op(::OpName"K0",::SiteType"Qubit",s1::Index,gamma)
    K0= [1 0;0 sqrt(1-gamma)]
    return itensor(K0,s1',s1)
end

function op(::OpName"K1",::SiteType"Qubit",s1::Index,gamma)
    K1 = [0 sqrt(gamma);0 0]
    return itensor(K1,s1',s1)
end

n = 10
s = siteinds("Qubit",n)
rho = MPO(s, "Id")

gamma = 0.1
for k = 1:size
    g1 = [("K0",k,gamma)]
    g2 = [("K1",k,gamma)]
    rho = apply(ops(g1,s),rho;apply_dag = true)+apply(ops(g2,s),rho;apply_dag = true)
end

But this doesn’t work and gives me errors.

Thanks

What errors do you get?

This is what I got

ERROR: MethodError: no method matching op(::Vector{Index{Int64}}, ::String, ::Int64, ::Float64)
Closest candidates are:
  op(::Vector{<:Index}, ::AbstractString, ::Integer...; kwargs...) at C:\Users\jisut\.julia\packages\ITensors\ZMKMP\src\physics\sitetype.jl:368
  op(::Vector{<:Index}, ::AbstractString, ::Integer, ::NamedTuple) at C:\Users\jisut\.julia\packages\ITensors\ZMKMP\src\physics\sitetype.jl:378
  op(::Vector{<:Index}, ::AbstractString, ::Tuple{Vararg{Integer}}; kwargs...) at C:\Users\jisut\.julia\packages\ITensors\ZMKMP\src\physics\sitetype.jl:362
  ...

Thanks

Here’s a corrected version of your code:

using ITensors
import ITensors: op

function op(::OpName"K0",::SiteType"Qubit",s1::Index;gamma)
    K0= [1 0;0 sqrt(1-gamma)]
    return itensor(K0,s1',s1)
end

function op(::OpName"K1",::SiteType"Qubit",s1::Index;gamma)
    K1 = [0 sqrt(gamma);0 0]
    return itensor(K1,s1',s1)
end

let
  n = 10
  s = siteinds("Qubit",n)
  rho = MPO(s, "Id")

  gamma = 0.1
  size = 4
  for k = 1:size
    g1 = [("K0",k,(gamma=gamma,))]
    g2 = [("K1",k,(gamma=gamma,))]
    rho = apply(ops(g1,s),rho;apply_dag = true)+apply(ops(g2,s),rho;apply_dag = true)
  end

return
end

Unfortunately the documentation on the named argument feature of the op function is not too good right now, which is why I went ahead and just fixed the code for you.

Basically the changes that I made were:

  • changed gamma to be a named argument of your two op function overloads (note the semicolon now separating it from the previous arguments)
  • changed the tuples inside of g1 and g2 to have gamma=gamma define a named tuple inside, which is how named parameters get passed through to the op function
  • I had to define size so that the code would run, but you may want to remove or change that line of course
  • I took your main code out of global scope: in general it’s a risky idea to run code in global scope for a number of reasons

For another example of this named argument feature of op, you can see this example code:
https://github.com/ITensor/ITensors.jl/blob/main/examples/gate_evolution/mpo_gate_evolution.jl
where the parameter τ gets passed through in a similar way.

1 Like

Hi Miles. Thanks a lot for the help. I appreciate it.

1 Like