Guide

Comparing the AGF with the diamond distance

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

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

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|>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")

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)


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)