#!/usr/bin/env python
# coding: utf-8
# # PyGSTi CHP Object Test
#
# This notebook is under construction and will have more description in the near future.
# In[1]:
from __future__ import print_function #python 2 & 3 compatibility
import pygsti
import numpy as np
from pygsti.modelmembers.operations import LinearOperator, StaticStandardOp, StochasticNoiseOp, DepolarizeOp, ComposedOp, EmbeddedOp
# ## LinearOperator and StaticStandardOp
#
# Now with 'chp' evotype.
# In[2]:
Gx = StaticStandardOp('Gxpi', evotype='chp')
print(Gx)
print(Gx._rep._chp_ops())
# In[3]:
Gx.evotype.name
# In[4]:
# Can also make custom CHP operations
# Here I'm making a (deterministic) Hadamard on qubit 0 and CNOT on qubits 1 and 2
rep = pygsti.evotypes.chp.opreps.OpRep(['h 0', 'c 1 2'], state_space=3)
c = LinearOperator(rep, 'chp')
# In[5]:
print(c)
print(c._rep._chp_ops())
# In[6]:
print(StaticStandardOp('Gc20', evotype='chp'))
# ## StochasticNoiseOp and DepolarizeOp
#
# Now with 'chp' evotype
# In[7]:
nqubits = 1
scop = StochasticNoiseOp(nqubits, basis='pp', evotype='chp', initial_rates=[0.5, 0.1, 0.1], seed_or_state=2021)
print(scop)
for _ in range(4):
print(scop._rep._chp_ops())
# In[8]:
nqubits = 1
dop = DepolarizeOp(nqubits, basis='pp', evotype='chp', initial_rate=0.7, seed_or_state=2021)
print(dop)
for _ in range(4): # With seed 2021, pulls Z, I (no output), X, Y
print(dop._rep._chp_ops())
# ## ComposedOp + EmbeddedOp
# In[9]:
# ComposedOp
Gzx_composed = ComposedOp([StaticStandardOp('Gzpi', evotype='chp'), StaticStandardOp('Gxpi', evotype='chp')])
print(Gzx_composed)
print(Gzx_composed._rep._chp_ops())
#print(Gzx_composed.get_chp_str([2]))
# In[10]:
# EmbeddedOp
Gxi_embedded = EmbeddedOp(['Q0', 'Q1'], ['Q0'], StaticStandardOp('Gxpi', evotype='chp'))
print(Gxi_embedded)
print(Gxi_embedded._rep._chp_ops())
#print(Gxi_embedded.get_chp_str([5,7]))
# In[11]:
Gix_embedded = EmbeddedOp(['Q0', 'Q1'], ['Q1'], StaticStandardOp('Gxpi', evotype='chp'))
print(Gix_embedded)
print(Gix_embedded._rep._chp_ops())
#print(Gix_embedded.get_chp_str([5,7]))
# In[12]:
# EmbeddedOp made of ComposedOps
Gzx_comp_embed = EmbeddedOp(['Q0', 'Q1', 'Q2', 'Q3'], ['Q1'], Gzx_composed)
print(Gzx_comp_embed)
print(Gzx_comp_embed._rep._chp_ops())
#print(Gzx_comp_embed.get_chp_str([5, 6, 7, 8]))
# ## CHPForwardSimulator + Explicit Model
# In[22]:
#This is the directory where the chp directory lives during github testing, replace this with the
#correct directory for your personal installation
pygsti.evotypes.chp.chpexe = 'chp'
sim = pygsti.forwardsims.WeakForwardSimulator(shots=100)
# In[23]:
#Initialize an empty Model object
model = pygsti.models.ExplicitOpModel(['Q0', 'Q1'], simulator=sim, evotype='chp')
def make_2Q_op(name0, name1):
return ComposedOp([
EmbeddedOp(['Q0', 'Q1'], ['Q0'], StaticStandardOp(name0, evotype='chp')),
EmbeddedOp(['Q0', 'Q1'], ['Q1'], StaticStandardOp(name1, evotype='chp')),
])
#Populate the Model object with states, effects, gates
# For CHP, prep must be all-zero ComputationalSPAMVec
# and povm must be ComputationalBasisPOVM
model['rho0'] = pygsti.modelmembers.states.ComputationalBasisState([0, 0], evotype='chp')
model['Mdefault'] = pygsti.modelmembers.povms.ComputationalBasisPOVM(2, evotype='chp')
model['Gii'] = make_2Q_op('Gi', 'Gi')
model['Gxi'] = make_2Q_op('Gxpi', 'Gi')
model['Gix'] = make_2Q_op('Gi', 'Gxpi')
model['Gxx'] = make_2Q_op('Gxpi', 'Gxpi')
model['Gyi'] = make_2Q_op('Gypi', 'Gi')
model['Giy'] = make_2Q_op('Gi', 'Gypi')
model['Gyy'] = make_2Q_op('Gypi', 'Gypi')
print(model)
# In[24]:
circ = pygsti.circuits.Circuit(['Gix'])
model.probabilities(circ)
# In[16]:
circ = pygsti.circuits.Circuit(['Gix', 'Gxi'])
model.probabilities(circ)
# In[17]:
circ = pygsti.circuits.Circuit(['rho0', 'Gxx', 'Mdefault'])
model.probabilities(circ)
# ## Advanced State Prep and Measurement
#
# TODO: This section does not work due to non-CHP related issues. Come back to this once other issues are fixed.
#
# ### State Prep
# In[18]:
#Initialize an empty Model object
prep01_model = pygsti.models.ExplicitOpModel(['Q0', 'Q1'], simulator=sim, evotype='chp')
# Make a ComputationalSPAMVec with one bit in 1 state
prep01_model.preps['rho0'] = pygsti.modelmembers.states.ComputationalBasisState([0, 1], evotype='chp')
prep01_model.povms['Mdefault'] = pygsti.modelmembers.povms.ComputationalBasisPOVM(2, evotype='chp')
circ = pygsti.circuits.Circuit([])
prep01_model.probabilities(circ)
# In[19]:
#Initialize an empty Model object
prep00noise_model = pygsti.models.ExplicitOpModel(['Q0', 'Q1'], simulator=sim, evotype='chp')
# Make a ComposedSPAMVec where second qubit has X error
rho0 = pygsti.modelmembers.states.ComposedState(
pygsti.modelmembers.states.ComputationalBasisState([0, 0], evotype='chp'), # Pure SPAM vec is 00 state
make_2Q_op('Gi', 'Gxpi2')) # Second qubit has X(pi/2) error (partial flip on qubit 1)
prep00noise_model['rho0'] = rho0
prep00noise_model['Mdefault'] = pygsti.modelmembers.povms.ComputationalBasisPOVM(2, 'chp')
circ = pygsti.circuits.Circuit([])
prep00noise_model.probabilities(circ)
# In[21]:
#Initialize an empty Model object
prep11noise_model = pygsti.models.ExplicitOpModel(['Q0', 'Q1'], simulator=sim, evotype='chp')
# Make a ComposedSPAMVec where second qubit has X error AND is initialized to 1 state
rho0 = pygsti.modelmembers.states.ComposedState(
pygsti.modelmembers.states.ComputationalBasisState([1, 1], evotype='chp'), # Pure SPAM vec is 00 state
make_2Q_op('Gi', 'Gxpi2')) # Second qubit has X(pi/2) error (partial flip on qubit 1)
prep11noise_model['rho0'] = rho0
prep11noise_model['Mdefault'] = pygsti.modelmembers.povms.ComputationalBasisPOVM(2, 'chp')
circ = pygsti.circuits.Circuit([])
prep11noise_model.probabilities(circ)
# ### Measurement
# In[47]:
make_2Q_op('Gi', 'Gxpi2')._rep
# In[54]:
##Initialize an empty Model object
#povm01_model = pygsti.models.ExplicitOpModel(['Q0', 'Q1'], simulator=sim, evotype='chp')
#
## Make a measurement with a bitflip error on qubit 1
#povm01_model.preps['rho0'] = pygsti.modelmembers.states.ComputationalBasisState([0, 1], evotype='chp')
#povm01_model.povms['Mdefault'] = pygsti.modelmembers.povms.ComposedPOVM(
# make_2Q_op('Gi', 'Gxpi2'),
# pygsti.modelmembers.povms.ComputationalBasisPOVM(2, evotype='chp'),
# mx_basis='pp')
#
#povm01_model._primitive_povm_label_dict['Mdefault'] = povm01_model['Mdefault']
#
#circ = pygsti.circuits.Circuit([])
#povm01_model.probabilities(circ)
# ## CHPForwardSimulator + LocalNoiseModel
# In[55]:
# Step 1: Define stochastic Pauli noise operators
# Note that the probabilities here are the "error rates" that would be model parameters (currently just static)
noise_1q = StochasticNoiseOp(1, basis='pp', evotype='chp', initial_rates=[0.1, 0.01, 0.01], seed_or_state=2021)
# Also need two-qubit version
# Here we just make it independent stochastic Pauli noise
noise_2q = ComposedOp([EmbeddedOp([0, 1], [0], noise_1q), EmbeddedOp([0, 1], [1], noise_1q)])
# In[24]:
# Step 2: Define gate dict of noisy gates
# Using equivalent of XYICNOT modelpack
gatedict = {}
gatedict['Gi'] = noise_1q
gatedict['Gx'] = ComposedOp([StaticStandardOp('Gxpi', evotype='chp'), noise_1q])
gatedict['Gy'] = ComposedOp([StaticStandardOp('Gypi', evotype='chp'), noise_1q])
# Note that first Gcnot is now key in model, whereas second Gcnot is a standard gatename known to CHPOp constructor
gatedict['Gcnot'] = ComposedOp([StaticStandardOp('Gcnot', evotype='chp'), noise_2q])
# In[25]:
from pygsti.models.localnoisemodel import LocalNoiseModel
from pygsti.modelmembers.states import ComputationalBasisState
from pygsti.modelmembers.povms import ComputationalBasisPOVM
from pygsti.processors import QubitProcessorSpec
pspec = QubitProcessorSpec(4, list(gatedict.keys()), geometry='line',
availability={'Gcnot': [(0,1),(1,2),(2,3)]})
rho0 = ComputationalBasisState([0,]*4, evotype='chp')
Mdefault = ComputationalBasisPOVM(4, evotype='chp')
ln_model = LocalNoiseModel(pspec, gatedict=gatedict, prep_layers=[rho0], povm_layers=[Mdefault],
simulator=sim, evotype='chp')
# In[26]:
# Step 4: Profit?? Worked way too quickly...
def print_implicit_model_blocks(mdl, showSPAM=False):
if showSPAM:
print('State prep building blocks (.prep_blks):')
for blk_lbl,blk in mdl.prep_blks.items():
print(" " + blk_lbl, ": ", ', '.join(map(str,blk.keys())))
print()
print('POVM building blocks (.povm_blks):')
for blk_lbl,blk in mdl.povm_blks.items():
print(" " + blk_lbl, ": ", ', '.join(map(str,blk.keys())))
print()
print('Operation building blocks (.operation_blks):')
for blk_lbl,blk in mdl.operation_blks.items():
print(" " + blk_lbl, ": ", ', '.join(map(str,blk.keys())))
print()
print_implicit_model_blocks(ln_model, showSPAM=True)
# In[27]:
print(ln_model.prep_blks['layers']['rho0'])
# In[28]:
print(ln_model.operation_blks['gates']['Gx'])
# In[29]:
Gcnot_layer_op = ln_model.operation_blks['layers']['Gcnot', 1, 2]
print(ln_model.operation_blks['layers']['Gcnot', 1, 2])
# In[30]:
# Step 5: Actually run circuits with local noise model
circ = pygsti.circuits.Circuit([('Gx', 1)], num_lines=4)
ln_model.probabilities(circ)
# In[31]:
circ = pygsti.circuits.Circuit([('Gx', 1), ('Gcnot', 1, 2)], num_lines=4)
ln_model.probabilities(circ)
# In[32]:
# Could also define correlated noise for 2-qubit error?
pp = pygsti.baseobjs.Basis.cast('pp', 16)
rates_2q = [0.01,]*15
rates_2q[pp.labels.index('XX')] = 0.1 # Set XX to much higher
noise_2q_correlated = StochasticNoiseOp(2, basis='pp', evotype='chp', initial_rates=rates_2q, seed_or_state=2021)
gatedict = {}
gatedict['Gi'] = noise_1q
gatedict['Gx'] = ComposedOp([StaticStandardOp('Gxpi', evotype='chp'), noise_1q])
gatedict['Gy'] = ComposedOp([StaticStandardOp('Gypi', evotype='chp'), noise_1q])
# Note that first Gcnot is now key in model, whereas second Gcnot is a standard gatename known to CHPOp constructor
gatedict['Gcnot'] = ComposedOp([StaticStandardOp('Gcnot', evotype='chp'), noise_2q_correlated])
# In[34]:
rho0 = ComputationalBasisState([0,]*4, evotype='chp')
Mdefault = ComputationalBasisPOVM(4, evotype='chp')
sim = pygsti.forwardsims.WeakForwardSimulator(shots=100)
ln_model_corr = LocalNoiseModel(pspec, gatedict=gatedict, prep_layers=[rho0], povm_layers=[Mdefault],
simulator=sim, evotype='chp')
# In[35]:
# Now the CNOT gates have a 2-qubit stochastic gate instead of independent 1-qubit ones
print(ln_model_corr.operation_blks['layers']['Gcnot', 1, 2])
# In[36]:
circ = pygsti.circuits.Circuit([('Gx', 1)], num_lines=4)
ln_model_corr.probabilities(circ)
# In[37]:
circ = pygsti.circuits.Circuit([('Gx', 1), ('Gcnot', 1, 2)], num_lines=4)
ln_model_corr.probabilities(circ)
# ## Crosstalk-Free Model Construction
# In[56]:
#import pygsti.models.modelconstruction as mc
#
#sim = pygsti.forwardsims.WeakForwardSimulator(shots=100, base_seed=2021)
#
#pspec = QubitProcessorSpec(4, ['Gi', 'Gxpi', 'Gypi', 'Gcnot'], availability={'Gcnot': [(0,1),(1,2),(2,3)]})
#
## Use the same 2-qubit stochastic noise for CNOT as above
#ctf_model = mc.create_crosstalk_free_model(pspec,
# depolarization_strengths={'Gi': 0.1, 'Gxpi': 0.1},
# stochastic_error_probs={'Gypi': [0.1, 0.1, 0.1], 'Gcnot': rates_2q},
# simulator=sim, evotype='chp')
#
#print_implicit_model_blocks(ctf_model, showSPAM=True)
# In[57]:
#for name, gate in ctf_model.operation_blks['gates'].items():
# print(f'Gate {name}')
# print(gate)
# print()
# In[59]:
#circ = pygsti.circuits.Circuit([('Gxpi', 1)], num_lines=4)
#ctf_model.probabilities(circ)
# In[60]:
#circ = pygsti.circuits.Circuit([('Gxpi', 1), ('Gcnot', 1, 2)], num_lines=4)
#ctf_model.probabilities(circ)
# In[61]:
# Marginalized POVMs now work!
#circ = pygsti.circuits.Circuit([('Gxpi', 1), ('Gcnot', 1, 2)])
#ctf_model.probabilities(circ)
# In[62]:
# Let's try a model with only readout error
#sim = pygsti.forwardsims.CHPForwardSimulator(chpexe, shots=1000) # Bump up shots for better noise resolution
#
#ctf_povm_model = mc.create_crosstalk_free_model(pspec,
# stochastic_error_probs={'povm': [0.05, 0.0, 0.0]}, # 5% X error on prep
# simulator=sim, evotype='chp')
# In[63]:
#circ = pygsti.circuits.Circuit([])
#ctf_povm_model.probabilities(circ) # Expect about 80% all 0, 5% on weight one errors, 0.25% on weight 2, etc.
# In[ ]: