Guide

In this page several examples of usage will be documented.

Comparing the AGF with the diamond distance

First needed modules are loaded.

using ConvolutionHyper
using SchattenNorms
using QuantumChannels
using LinearAlgebra

Then we introduce the basis to compute the PL rep:

base_proj = [
[1 0 0;
0 0 0;
0 0 0],
[0 0 0;
1 0 0;
0 0 0],
[0 0 0;
0 0 0;
1 0 0],
[0 1 0;
0 0 0;
0 0 0],
[0 0 0;
0 1 0;
0 0 0],
[0 0 0;
0 0 0;
0 1 0],
[0 0 1;
0 0 0;
0 0 0],
[0 0 0;
0 0 1;
0 0 0],
[0 0 0;
0 0 0;
0 0 1]
];

Then, a function to compute the PL rep

function projrep(opbase)
    dim = 3
    output::Matrix{ComplexF64} = zeros(ComplexF64,(dim*dim, dim*dim))
    @inbounds for i::Int in 1:(dim*dim), j::Int in 1:(dim*dim)
        output[i,j] = dot(base_proj[i],opbase(base_proj[j]))/dot(base_proj[i], base_proj[i])
    end
    output
end

Then, a couple of Pauli channels are defined:

pt1 = random(9,.98)
pt2 = random(9,.98)
pc1 = x -> paulichannel(x, pt1)
pc2 = x -> paulichannel(x, pt2)
rep1 = projrep(pc1)
rep2 = projrep(pc2)

Finally we compute the diamond distance between them.

ddist(rep1,rep2)

We now introduce functions to compute the diamond distance for a gate and a gate set.

function diamond(gate::Gate)
    x,y,z = gate.word
    errorphase = gate.errorphase
    errorrot = gate.errorrot

    unitary_diag = ConvolutionHyper.agate^y*ConvolutionHyper.bgate^z
    unitary_xpow = ConvolutionHyper.xgate^x

    noisy_channel = ρ -> errorrot(unitary_xpow*errorphase(unitary_diag*ρ*adjoint(unitary_diag))*adjoint(unitary_xpow))
    channel_agf = ρ -> adjoint(unitary_xpow*unitary_diag)*noisy_channel(ρ)*(unitary_xpow*unitary_diag)

    rep1 = projrep(noisy_channel)
    rep2 = projrep(channel_agf)

    ddist(rep1,rep2)

    # return (3*tr(plrep(channel_agf))+9)/(36)
end

function diamond(gateset::Vector{Gate})
    sum(map(diamond,gateset))/length(gateset)
end

And then we compare the results:

for _ in 1:10
    error = Error(ConvolutionHyper.diagerror, ConvolutionHyper.overrotation, .9999, .99)
    gateset = ConvolutionHyper.compute_gateset(error)
    valores = valuesgateset(gateset)
    theo = ((3/9)*dot(valores, [1,1,1,3,3])+1)/4
    real = diamond(gateset)
    percentage_error = 100*abs(real-theo)/abs(real)
    println(percentage_error)
    # ConvolutionHyper.tofile("diag9999rot99_take1.csv", percentage_error)
end

Comparing eigenvalue AGF with fitted AGF

We load the needed packages.

using ConvolutionHyper
using LinearAlgebra
using LsqFit: curve_fit, coef
using Plots
using ZChop
using DelimitedFiles

Repeat one million of times the comparison between the real AGF (computing the average gate fidelity over the gate set) and the eigenvalue AGF (using the expression with the eigenvalues). Uses the function tofile to store the results.

for _ in 1:10^6
    error = Error(ConvolutionHyper.diagerror, ConvolutionHyper.overrotation, .9999, .99)
    gateset = ConvolutionHyper.compute_gateset(error)
    valores = valuesgateset(gateset)
    theo = ((3/9)*dot(valores, [1,1,1,3,3])+1)/4
    real = agf(gateset)
    percentage_error = 100*abs(real-theo)/abs(real)
    ConvolutionHyper.tofile("diag9999rot99_take1.csv", percentage_error)
end

Read the output and compute the histogram of the differences:

begin
    differences = readdlm("./diag9999rot99_take1.csv")
    differences|>histogram
end

Compute a random gate set.

begin
    error = Error(ConvolutionHyper.diagerror, ConvolutionHyper.overrotation, .9999, .99)
    gateset = ConvolutionHyper.compute_gateset(error)
end

Then set up the experiment to fit using the ESPRIT method

interval = 2:2:100
long_experiment(interval, 150, error, "sp0_v2.csv", "spP_v2.csv")
sp_zero = readdlm("sp0_v3.csv")
sp_plus = readdlm("spP_v3.csv")

begin
    values0 = spritfit(sp_zero,3)
    # p1 = values0[end]^(-1/(3*2))
    p1x = values0[end]^(-1/(3))
    valuesP = spritfit(sp_plus,3)
    # p2 = valuesP[end]^(-1/(3*2))
    p2x = valuesP[end]^(-1/(3))
    fitesprit = (1+3*(1+2*p1x+6*p2x)/9)/(3+1)
end

Then, we compute the fit for a straight line:

begin
    @. model(x,p) = p[1]+p[2]*x
    p0 = [.1, 1.]

    fitzero = curve_fit(model, interval, sp_zero[:,1], p0)
    fitplus = curve_fit(model, interval, sp_plus[:,1], p0)
    
    p1 = coef(fitzero)[2]|> exp
    p2 = coef(fitplus)[2]|> exp
    fit = (3*(1+2*p1+6*p2)/9+1)/4
end

Finally, we compare the different values

100*abs(real-fit)/abs(real)
100*abs(real-theo)/abs(real)
100*abs(real-fitesprit)/abs(real)

Setting up a different error channel.

It is possible easily add a different error channel. For instance, useful for making errors gate independent.

The first point is testing the function compute_gateset:

ConvolutionHyper.compute_gatesetMethod
compute_gateset(error::Error)

Function that uses the structure Error to compute a gate set. Specifically, it takes error a structure Error and outputs a list of structures Gate where each one has the error inclued in Error.errorphase, Error.errorrot, Error.fidelityphase, and Error.fidelityrot.

Examples

julia> indep = x -> identity
julia> error = Error(indep, indep, .9999, .99) # ideal gates 
julia> gateset = compute_gateset(error)

See also

overrotation Error

source

Then we can use the function paulichannel_byfidelity to assign a different Pauli channel to each gate set member.

ConvolutionHyper.paulichannel_byfidelityMethod
paulichannel_byfidelity(fidelity)

For a given fidelity value fidelity, returns a function corresponding to a the action of a (each time different) Pauli channel.

Examples

julia> random_paulichannel = paulichannel_byfidelity(0.99)
julia> random_paulichannel(diagm([1.,0,0]))
source

More interestingly, is how to construct a gate-independent error configuration.

julia> random_paulichannel = paulichannel_byfidelity(0.99);
julia> error =  Error(x -> identity, x -> random_paulichannel, .9999, .99) # using a constant anonymous function
julia> gateset = compute_gateset(error)