State preparation using variational quantum circuit ansatz

Hi everyone,

Not sure if this question truly belongs to the ITensor genre, but anyway I already struggled for quite some time before I decided to post here for help.

So basically my goal is to perform state preparation: to approximate a target state obtained via Trotterized time evolution of a simple XY model with a variational ansatz, similar to the way as done in: ITensors.jl/src/lib/ITensorMPS/examples/autodiff/circuit_optimization/vqe.jl at main · ITensor/ITensors.jl · GitHub

The time evolution code is easy (so I won’t show it here, and I benchmarked already with small system sizes). The issue is the variational optimization (that’s why I wonder if this is a truly question related to ITensor or not). I am trying to using a layer ansatz with R_n gates and CNOT gates which are different from the ansatz given in the above example link for VQE. For a small system as N=6, no matter how many depths (ndepth in the code below; each depth means one odd layer and one even layer) I use, I am not able to obtain a converged result, as the loss function got stuck at about -0.75. Ideally, it should go to -0.999999\cdots.

I suspect that it got stuck in a local minimum? To this end, I think this might have something to do with the classical optimization part. I’m not that familiar with the \texttt{optimkit.jl}, but it seems that it has not been updated on github for some time or so? Should I explore to find a good optimization package in Julia?

Thank you!

s = siteinds("Qubit", nsites)
ψ0 = ψ_initial  # a trivial initial state with |010101...>
function loss(θ0)
    nsites = length(ψ0)
    s = siteinds(ψ0)
    order = 1
    VQC_total_ansatz = []
    for d in range(1,step=1,length=Int64(ndepth))
        # odd sub-layer
        CX_odd_layer = [];
        Rn_odd_layer = [];
        VQC_odd_layer = [];
        for i in CX_odd_ls
            CX_odd_layer = [CX_odd_layer; ("CX", (i, i + 1))];
        end
        
        for i in range(1,step=1,length=Int64(nsites))
            Rn_odd_layer = [Rn_odd_layer; ("Rn", (i,), (θ=θ0[order],ϕ=θ0[order+1],λ=θ0[order+2]))];
            order = order + 3;
        end
        VQC_odd_layer = [VQC_odd_layer; CX_odd_layer; Rn_odd_layer];
    
        # even sub-layer
        CX_even_layer = [];
        Rn_even_layer = [];
        VQC_even_layer = [];
        for i in CX_even_ls
            CX_even_layer = [CX_even_layer; ("CX", (i, i + 1))];
        end
        
        for i in range(2,step=1,length=Int64(nsites-2))
            Rn_even_layer = [Rn_even_layer; ("Rn", (i,), (θ=θ0[order],ϕ=θ0[order+1],λ=θ0[order+2]))];
            order = order + 3;
        end
        VQC_even_layer = [VQC_even_layer; CX_even_layer; Rn_even_layer];
    
        VQC_single_ansatz = [VQC_odd_layer; VQC_even_layer]
        
        
        VQC_total_ansatz = [VQC_total_ansatz;VQC_single_ansatz];
    end
    U0 = VQC_total_ansatz;
    U1 = ops(U0, s)
    ψu = apply(U1, ψ0; cutoff=1e-8)
    return -abs(inner(ψf,ψu))^2

end

@show loss(θ0)

println("\nOptimize circuit with gradient optimization")

loss_∇loss(x) = (loss(x), convert(Vector, loss'(x)))
algorithm = LBFGS(; gradtol=gradtol, verbosity=2)
θₒₚₜ, lossₒₚₜ, ∇lossₒₚₜ, numfg, normgradhistory = optimize(loss_∇loss, θ0, algorithm)

@show loss(θₒₚₜ)

Seems reasonable to try a different optimization package besides OptimKit.jl, or maybe reassess the circuit ansatz you are using. I didn’t look carefully at your code, but I found that choosing a too restrictive ansatz could cause the optimization to get stuck in the way you describe.

I chose OptimKit.jl since it was easy to get working with ITensors.jl, since it is written in a very generic way that allows many kinds of inputs. I haven’t looked into the optimization packages in Julia for a while, I’d be curious to hear if other ones work better.

Thank you Matt. After some days of trials and errors, indeed the OptimKit.jl package only works for some cases of the quantum circuit recompilation. I also have to change between different optimization algorithms.

Perhaps one could try basinhopping techniques with L-BFGS-B algorithm (which I used for another tensor network based package), but this is beyond the scope of the discussion for ITensors.jl.

My primary reason for sharing those example codes was to show what is possible with AD in ITensor and also show it is easy to swap out other optimization algorithms, change the cost function, etc. (rather than show the absolute best way to do VQE with tensor networks). However, I am curious to hear if you find a better optimization method, if so let us know and maybe we can update the examples to point future users towards better options!

1 Like