-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started refactor to use dictionaries
- Loading branch information
Showing
9 changed files
with
591 additions
and
14 deletions.
There are no files selected for viewing
109 changes: 97 additions & 12 deletions
109
jupyter_notebooks/Examples/Propagatable error gens tutorial.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from pygsti.extras.errorgenpropagation.propagatableerrorgen import propagatableerrorgen | ||
from numpy import complex128 | ||
|
||
class errordict(dict): | ||
|
||
def __setitem__(self, __key: any, __value: any) -> None: | ||
if __key in self : | ||
super().__setitem__(__key,self[__key]+__value) | ||
else: | ||
super().__setitem__(__key,__value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
pygsti/extras/errorgenpropagation/errorpropagator_dev.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import stim | ||
from localstimerrorgen import * | ||
from numpy import abs,zeros, complex128 | ||
from numpy.linalg import multi_dot | ||
from scipy.linalg import expm | ||
from pygsti.tools.internalgates import standard_gatenames_stim_conversions | ||
from utilserrorgenpropagation import * | ||
|
||
|
||
def ErrorPropagator(circ,errorModel,MultiGateDict=None,BCHOrder=1,BCHLayerwise=False,NonMarkovian=False,MultiGate=False,ErrorLayerDef=False): | ||
if MultiGate and MultiGateDict is None: | ||
MultiGateDict=dict() | ||
stim_dict=standard_gatenames_stim_conversions() | ||
if MultiGate: | ||
for key in MultiGateDict: | ||
stim_dict[key]=stim_dict[MultiGateDict[key]] | ||
stim_layers=circ.convert_to_stim_tableau_layers(gate_name_conversions=stim_dict) | ||
stim_layers.pop(0) #Immediatly toss the first layer because it is not important, | ||
|
||
propagation_layers=[] | ||
if not BCHLayerwise or NonMarkovian: | ||
while len(stim_layers) != 0: | ||
top_layer=stim_layers.pop(0) | ||
for layer in stim_layers: | ||
top_layer = layer*top_layer | ||
propagation_layers.append(top_layer) | ||
else: | ||
propagation_layers = stim_layers | ||
|
||
if not ErrorLayerDef: | ||
errorLayers=buildErrorlayers(circ,errorModel,len(circ.line_labels)) | ||
else: | ||
errorLayers=[[errorModel]]*circ.depth #this doesn't work | ||
|
||
num_error_layers=len(errorLayers) | ||
|
||
fully_propagated_layers=[] | ||
for _ in range(0,num_error_layers-1): | ||
err_layer=errorLayers.pop(0) | ||
layer=propagation_layers.pop(0) | ||
new_error_layer=[] | ||
for err_order in err_layer: | ||
new_error_dict=dict() | ||
for key in err_order: | ||
propagated_error_gen=key.propagate_error_gen_tableau(layer,err_order[key]) | ||
new_error_dict[propagated_error_gen[0]]=propagated_error_gen[1] | ||
new_error_layer.append(new_error_dict) | ||
if BCHLayerwise and not NonMarkovian: | ||
following_layer = errorLayers.pop(0) | ||
new_errors=BCH_Handler(err_layer,following_layer,BCHOrder) | ||
errorLayers.insert(new_errors,0) | ||
else: | ||
fully_propagated_layers.append(new_error_layer) | ||
|
||
fully_propagated_layers.append(errorLayers.pop(0)) | ||
if BCHLayerwise and not NonMarkovian: | ||
final_error=dict() | ||
for order in errorLayers[0]: | ||
for error in order: | ||
if error in final_error: | ||
final_error[error]=final_error[error]+order[error] | ||
else: | ||
final_error[error]=order[error] | ||
return final_error | ||
|
||
elif not BCHLayerwise and not NonMarkovian: | ||
simplified_EOC_errors=dict() | ||
if BCHOrder == 1: | ||
for layer in fully_propagated_layers: | ||
for order in layer: | ||
for error in order: | ||
if error in simplified_EOC_errors: | ||
simplified_EOC_errors[error]=simplified_EOC_errors[error]+order[error] | ||
else: | ||
simplified_EOC_errors[error]=order[error] | ||
|
||
else: | ||
Exception("Higher propagated through Errors are not Implemented Yet") | ||
return simplified_EOC_errors | ||
|
||
else: | ||
return fully_propagated_layers | ||
|
||
|
||
|
||
def buildErrorlayers(circ,errorDict,qubits): | ||
ErrorGens=[] | ||
#For the jth layer of each circuit | ||
for j in range(circ.depth): | ||
l = circ.layer(j) # get the layer | ||
errorLayer=dict() | ||
for _, g in enumerate(l): # for gate in layer l | ||
gErrorDict = errorDict[g.name] #get the errors for the gate | ||
p1=qubits*'I' # make some paulis why? | ||
p2=qubits*'I' | ||
for errs in gErrorDict: #for an error in the accompanying error dictionary | ||
errType=errs[0] | ||
paulis=[] | ||
for ind,el in enumerate(g): #enumerate the gate ind =0 is name ind = 1 is first qubit ind = 2 is second qubit | ||
if ind !=0: #if the gate element of concern is not the name | ||
p1=p1[:el] + errs[1][ind-1] +p1[(el+1):] | ||
|
||
paulis.append(stim.PauliString(p1)) | ||
if errType in "CA": | ||
for ind,el in enumerate(g): | ||
if ind !=0: | ||
p2=p2[:el] + errs[2][ind-1] +p2[(el+1):] | ||
paulis.append(stim.PauliString(p2)) | ||
errorLayer[localstimerrorgen(errType,paulis)]=gErrorDict[errs] | ||
ErrorGens.append([errorLayer]) | ||
return ErrorGens | ||
''' | ||
Inputs: | ||
_______ | ||
err_layer (list of dictionaries) | ||
following_layer (list of dictionaries) | ||
BCHOrder: | ||
''' | ||
def BCH_Handler(err_layer,following_layer,BCHOrder): | ||
new_errors=[] | ||
for curr_order in range(0,BCHOrder): | ||
working_order=dict() | ||
#add first order terms into new layer | ||
if curr_order == 0: | ||
for error_key in err_layer[curr_order]: | ||
working_order[error_key]=err_layer[curr_order][error_key] | ||
for error_key in following_layer[curr_order]: | ||
working_order[error_key]=following_layer[curr_order[error_key]] | ||
new_errors.append(working_order) | ||
|
||
elif curr_order ==1: | ||
working_order={} | ||
for error1 in err_layer[curr_order-1]: | ||
for error2 in following_layer[curr_order-1]: | ||
errorlist = commute_errors(error1,error2,BCHweight=1/2*err_layer[error1]*following_layer[error2]) | ||
for error_tuple in errorlist: | ||
working_order[error_tuple[0]]=error_tuple[1] | ||
if len(err_layer)==2: | ||
for error_key in err_layer[1]: | ||
working_order[error_key]=err_layer[1][error_key] | ||
if len(following_layer)==2: | ||
for error_key in following_layer[1]: | ||
working_order[error_key]=following_layer[1][error_key] | ||
new_errors.append(working_order) | ||
|
||
else: | ||
Exception("Higher Orders are not Implemented Yet") | ||
return new_errors | ||
|
||
# There's a factor of a half missing in here. | ||
def nm_propagators(corr, Elist,qubits): | ||
Kms = [] | ||
for idm in range(len(Elist)): | ||
Am=zeros([4**qubits,4**qubits],dtype=complex128) | ||
for key in Elist[idm][0]: | ||
Am += key.toWeightedErrorBasisMatrix() | ||
# This assumes that Elist is in reverse chronological order | ||
partials = [] | ||
for idn in range(idm, len(Elist)): | ||
An=zeros([4**qubits,4**qubits],dtype=complex128) | ||
for key2 in Elist[idn][0]: | ||
An = key2.toWeightedErrorBasisMatrix() | ||
partials += [corr[idm,idn] * Am @ An] | ||
partials[0] = partials[0]/2 | ||
Kms += [sum(partials,0)] | ||
return Kms | ||
|
||
def averaged_evolution(corr, Elist,qubits): | ||
Kms = nm_propagators(corr, Elist,qubits) | ||
return multi_dot([expm(Km) for Km in Kms]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from pygsti.baseobjs.errorgenlabel import ElementaryErrorgenLabel | ||
from pygsti.extras.errorgenpropagation.utilspygstistimtranslator import * | ||
import stim | ||
from numpy import array,kron | ||
from pygsti.tools import change_basis | ||
from pygsti.tools.lindbladtools import create_elementary_errorgen | ||
|
||
class localstimerrorgen(ElementaryErrorgenLabel): | ||
|
||
|
||
''' | ||
Initiates the errorgen object | ||
Inputs: | ||
______ | ||
errorgen_type: characture can be set to 'H' Hamiltonian, 'S' Stochastic, 'C' Correlated or 'A' active following the conventions | ||
of the taxonomy of small markovian errorgens paper | ||
basis_element_labels | ||
Outputs: | ||
Null | ||
''' | ||
def __init__(self,errorgen_type: str ,basis_element_labels: list): | ||
self.errorgen_type=str(errorgen_type) | ||
self.basis_element_labels=tuple(basis_element_labels) | ||
|
||
''' | ||
hashes the error gen object | ||
''' | ||
def __hash__(self): | ||
pauli_hashable=[] | ||
for pauli in self.basis_element_labels: | ||
pauli_hashable.append(str(pauli)) | ||
return hash((self.errorgen_type,tuple(pauli_hashable))) | ||
|
||
def labels_to_strings(self): | ||
strings=[] | ||
for paulistring in self.basis_element_labels: | ||
strings.append(str(paulistring)[1:].replace('_',"I")) | ||
return tuple(strings) | ||
|
||
|
||
''' | ||
checks and if two error gens have the same type and labels | ||
''' | ||
def __eq__(self, other): | ||
return (self.errorgen_type == other.errorgen_type | ||
and self.basis_element_labels == other.basis_element_labels) | ||
|
||
''' | ||
displays the errorgens as strings | ||
''' | ||
def __str__(self): | ||
return self.errorgen_type + "(" + ",".join(map(str, self.basis_element_labels)) + ")" | ||
|
||
|
||
def __repr__(self): | ||
return str((self.errorgen_type, self.basis_element_labels)) | ||
|
||
''' | ||
Returns the errorbasis matrix for the associated errorgenerator mulitplied by its error rate | ||
input: A pygsti defined matrix basis by default can be pauli-product, gellmann 'gm' or then pygsti standard basis 'std' | ||
functions defaults to pauli product if not specified | ||
''' | ||
def toWeightedErrorBasisMatrix(self,weight=1.0,matrix_basis='pp'): | ||
PauliDict={ | ||
'I' : array([[1.0,0.0],[0.0,1.0]]), | ||
'X' : array([[0.0j, 1.0+0.0j], [1.0+0.0j, 0.0j]]), | ||
'Y' : array([[0.0, -1.0j], [1.0j, 0.0]]), | ||
'Z' : array([[1.0, 0.0j], [0.0j, -1.0]]) | ||
} | ||
paulis=[] | ||
for paulistring in self.basis_element_labels: | ||
for idx,pauli in enumerate(paulistring): | ||
if idx == 0: | ||
pauliMat = PauliDict[pauli] | ||
else: | ||
pauliMat=kron(pauliMat,PauliDict[pauli]) | ||
paulis.append(pauliMat) | ||
if self.errorgen_type in 'HS': | ||
return weight*change_basis(create_elementary_errorgen(self.errorgen_type,paulis[0]),'std',matrix_basis) | ||
else: | ||
return weight*change_basis(create_elementary_errorgen(self.errorgen_type,paulis[0],paulis[1]),'std',matrix_basis) | ||
|
||
def propagate_error_gen_tableau(self, slayer,weight): | ||
new_basis_labels = [] | ||
weightmod = 1 | ||
for pauli in self.basis_element_labels: | ||
temp = slayer(pauli) | ||
weightmod=weightmod*temp.sign | ||
temp=temp*temp.sign | ||
new_basis_labels.append(temp) | ||
|
||
return (localstimerrorgen(self.errorgen_type,new_basis_labels),weightmod*weight) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.