Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pygsti/baseobjs/statespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ def qudit_udims(self):
"""Integer Hilbert (unitary operator) space dimensions of the qudits in ths quantum state space."""
return self._qudit_udims


@property
def udim(self):
"""
Expand Down
15 changes: 9 additions & 6 deletions pygsti/modelmembers/instruments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@


def instrument_type_from_op_type(op_type):
"""Decode an op type into an appropriate instrument type.
"""
Decode an op type into an appropriate instrument type.

Parameters:
-----------
Expand All @@ -38,13 +39,13 @@ def instrument_type_from_op_type(op_type):
# Limited set (only matching what is in convert)
instr_conversion = {
'auto': 'full',
'static unitary': 'static unitary',
'static clifford': 'static clifford',
'static unitary': 'static',
'static clifford': 'static',
'static': 'static',
'full': 'full',
'full TP': 'full TP',
'full CPTP': 'full CPTP',
'full unitary': 'full unitary',
'full CPTP': 'full TP',
'full unitary': 'full',
}

instr_type_preferences = []
Expand All @@ -71,6 +72,8 @@ def instrument_type_from_op_type(op_type):

return instr_type_preferences

def create_from_instrument_effects():
pass

def convert(instrument, to_type, basis, ideal_instrument=None, flatten_structure=False):
"""
Expand Down Expand Up @@ -121,7 +124,7 @@ def convert(instrument, to_type, basis, ideal_instrument=None, flatten_structure

if to_type == "full TP":
return TPInstrument(list(instrument.items()), instrument.evotype, instrument.state_space)
elif to_type in ("full", "static", "static unitary"):
elif to_type in ("full", "static"):
from ..operations import convert as _op_convert
ideal_items = dict(ideal_instrument.items()) if (ideal_instrument is not None) else {}
members = [(k, _op_convert(g, to_type, basis, ideal_items.get(k, None), flatten_structure))
Expand Down
1 change: 1 addition & 0 deletions pygsti/modelmembers/operations/embeddedop.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pygsti.baseobjs.statespace import StateSpace as _StateSpace
from pygsti.baseobjs.errorgenlabel import GlobalElementaryErrorgenLabel as _GlobalElementaryErrorgenLabel, LocalElementaryErrorgenLabel as _LocalElementaryErrorgenLabel
from pygsti import SpaceT

class EmbeddedOp(_LinearOperator):
"""
An operation containing a single lower (or equal) dimensional operation within it.
Expand Down
4 changes: 2 additions & 2 deletions pygsti/models/cloudnoisemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import scipy.sparse as _sps

from pygsti.baseobjs import statespace as _statespace
from pygsti.models.implicitmodel import ImplicitOpModel as _ImplicitOpModel, _init_spam_layers
from pygsti.models.implicitmodel import ImplicitOpModel as _ImplicitOpModel
from pygsti.models.layerrules import LayerRules as _LayerRules
from pygsti.models.memberdict import OrderedMemberDict as _OrderedMemberDict
from pygsti.evotypes import Evotype as _Evotype
Expand Down Expand Up @@ -306,7 +306,7 @@ def __init__(self, processor_spec, gatedict,
# used to specify which gate parameters should be amplifiable by germs for a given cloud (?)
# TODO CHECK THIS

_init_spam_layers(self, prep_layers, povm_layers) # SPAM
self._init_spam_layers(self, prep_layers, povm_layers) # SPAM

printer.log("DONE! - created Model with nqudits=%d and op-blks=" % self.state_space.num_qudits)
for op_blk_lbl, op_blk in self.operation_blks.items():
Expand Down
64 changes: 58 additions & 6 deletions pygsti/models/explicitmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ def flagfn(typ): return {'auto_embed': True, 'match_parent_statespace': True,
self.preps = _OrderedMemberDict(self, default_prep_type, prep_prefix, flagfn("state"))
self.povms = _OrderedMemberDict(self, default_povm_type, povm_prefix, flagfn("povm"))
self.operations = _OrderedMemberDict(self, default_gate_type, gate_prefix, flagfn("operation"))
self.instruments = _OrderedMemberDict(self, default_instrument_type, instrument_prefix, flagfn("instrument"))
self.instruments = _OrderedMemberDict(self, default_instrument_type, instrument_prefix,
{'auto_embed': False, 'match_parent_statespace': True,
'match_parent_evotype': True, 'cast_to_type': 'instrument'})
self.factories = _OrderedMemberDict(self, default_gate_type, gate_prefix, flagfn("factory"))
self.effects_prefix = effect_prefix
self._default_gauge_group = None
Expand Down Expand Up @@ -222,6 +224,8 @@ def _embed_operation(self, op_target_labels, op_val, force=False):
return op_val # if gate operates on full dimension, no need to embed.

return _op.EmbeddedOp(self.state_space, op_target_labels, op_val)

#TODO: Add an equivalent method for embedding instruments automatically.

@property
def default_gauge_group(self):
Expand Down Expand Up @@ -1552,7 +1556,10 @@ def create_processor_spec(self, qudit_labels='auto'):
gate_unitaries = _collections.OrderedDict()
all_sslbls = self.state_space.sole_tensor_product_block_labels
all_udims = [self.state_space.label_udimension(lbl) for lbl in all_sslbls]
sslbl_to_udim = {lbl:udim for lbl,udim in zip(all_sslbls, all_udims)}
all_qubits = all([udim == 2 for udim in all_udims])
availability = {}
instrument_names = set(lbl.name for lbl in self.instruments)

def extract_unitary(Umx, U_sslbls, extracted_sslbls):
if extracted_sslbls is None: return Umx # no extraction to be done
Expand All @@ -1575,7 +1582,7 @@ def extract_unitary(Umx, U_sslbls, extracted_sslbls):
U_extracted[ii, jj] = Umx[i, j]
return U_extracted

def add_availability(opkey, op):
def add_availability_gate(opkey, op):
if opkey == _Label(()) or opkey.is_simple:
if opkey == _Label(()): # special case: turn empty tuple labels into "{idle}" gate in processor spec
gn = "{idle}"
Expand All @@ -1598,16 +1605,57 @@ def add_availability(opkey, op):
availability[gn].append(sslbls)
else:
availability[gn] = [sslbls]

elif sslbls not in availability[gn]:
availability[gn].append(sslbls)

else: # a COMPOUND label with components => process each component separately
for component in opkey.components:
add_availability(component, None) # recursive call - the reason we need this to be a function!
add_availability_gate(component, None) # recursive call - the reason we need this to be a function!

def add_availability_inst(opkey):
if opkey.is_simple:
gn = opkey.name
sslbls = opkey.sslbls
#if sslbls is not None:
# observed_sslbls.update(sslbls)
if gn in availability:
if sslbls not in availability[gn]:
availability[gn].append(sslbls)
else:
availability[gn] = [sslbls]

#observed_sslbls = set()
for opkey, op in self.operations.items(): # TODO: need to deal with special () idle label
add_availability(opkey, op)
add_availability_gate(opkey, op)

#process instruments:
nonstd_instruments = dict()
if self.instruments:
for instkey, inst in self.instruments.items():
add_availability_inst(instkey)

#create instrument specifiers.
seen_names = set()
from pygsti.processors.processorspec import InstrumentSpec as _InstrumentSpec
from pygsti.baseobjs.statespace import QubitSpace as _QubitSpace, QuditSpace as _QuditSpace
for instkey, inst in self.instruments.items():
instrument_specifiers = []
instrument_effect_labels = []
for lbl, inst_effect in inst.items():
instrument_effect_labels.append(lbl)
instrument_specifiers.append(inst_effect.to_dense())
name = instkey.name
if name not in seen_names:
instkey.sslbls
if all_qubits:
nonstd_instruments[name] = _InstrumentSpec(name, instrument_effect_labels, instrument_specifiers,
_QubitSpace(len(instkey.sslbls)))
else:

nonstd_instruments[name] = _InstrumentSpec(name, instrument_effect_labels, instrument_specifiers,
_QuditSpace(instkey.sslbls, [sslbl_to_udim[lbl] for lbl in instkey.sslbls]))
seen_names.add(name)

#Check that there aren't any undetermined unitaries
unknown_unitaries = [k for k, v in gate_unitaries.items() if v is None]
Expand All @@ -1623,17 +1671,21 @@ def add_availability(opkey, op):
if qudit_labels is None: # special case of legacy explicit models where all gates have availability [None]
qudit_labels = tuple(range(nqudits))



assert(len(qudit_labels) == nqudits), \
"Length of `qudit_labels` must equal %d (not %d)!" % (nqudits, len(qudit_labels))

if all([udim == 2 for udim in all_udims]):
return _QubitProcessorSpec(nqudits, list(gate_unitaries.keys()), gate_unitaries, availability,
qubit_labels=qudit_labels,
instrument_names=list(self.instruments.keys()), nonstd_instruments=self.instruments)
instrument_names=list(nonstd_instruments.keys()),
nonstd_instruments=nonstd_instruments)
else:
return _QuditProcessorSpec(qudit_labels, all_udims, list(gate_unitaries.keys()), gate_unitaries,
availability,
instrument_names=list(self.instruments.keys()), nonstd_instruments=self.instruments)
instrument_names=list(nonstd_instruments.keys()),
nonstd_instruments=nonstd_instruments)

def create_modelmember_graph(self):
return _MMGraph({
Expand Down
67 changes: 32 additions & 35 deletions pygsti/models/implicitmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from pygsti.models.layerrules import LayerRules as _LayerRules
from pygsti.forwardsims.forwardsim import ForwardSimulator as _FSim

from typing import Dict
ordereddict = Dict

class ImplicitOpModel(_mdl.OpModel):
"""
Expand Down Expand Up @@ -58,17 +60,12 @@ class ImplicitOpModel(_mdl.OpModel):
represented, allowing compatibility checks with (super)operator
objects.
"""
def __init__(self,
state_space,
layer_rules,
basis="pp",
simulator="auto",
evotype="densitymx"):
self.prep_blks = _collections.OrderedDict()
self.povm_blks = _collections.OrderedDict()
self.operation_blks = _collections.OrderedDict()
self.instrument_blks = _collections.OrderedDict()
self.factories = _collections.OrderedDict()
def __init__(self, state_space, layer_rules, basis="pp", simulator="auto", evotype="densitymx"):
self.prep_blks: ordereddict = dict()
self.povm_blks: ordereddict = dict()
self.operation_blks: ordereddict = dict()
self.instrument_blks: ordereddict = dict()
self.factories: ordereddict = dict()

super(ImplicitOpModel, self).__init__(state_space, basis, evotype, layer_rules, simulator)

Expand Down Expand Up @@ -370,27 +367,27 @@ def _from_nice_serialization(cls, state):
return mdl


def _init_spam_layers(model, prep_layers, povm_layers):
""" Helper function for initializing the .prep_blks and .povm_blks elements of an implicit model"""
# SPAM (same as for cloud noise model)
if prep_layers is None:
pass # no prep layers
elif isinstance(prep_layers, dict):
for rhoname, layerop in prep_layers.items():
model.prep_blks['layers'][_Label(rhoname)] = layerop
elif isinstance(prep_layers, _op.LinearOperator): # just a single layer op
model.prep_blks['layers'][_Label('rho0')] = prep_layers
else: # assume prep_layers is an iterable of layers, e.g. isinstance(prep_layers, (list,tuple)):
for i, layerop in enumerate(prep_layers):
model.prep_blks['layers'][_Label("rho%d" % i)] = layerop

if povm_layers is None:
pass # no povms
elif isinstance(povm_layers, _povm.POVM): # just a single povm - must precede 'dict' test!
model.povm_blks['layers'][_Label('Mdefault')] = povm_layers
elif isinstance(povm_layers, dict):
for povmname, layerop in povm_layers.items():
model.povm_blks['layers'][_Label(povmname)] = layerop
else: # assume povm_layers is an iterable of layers, e.g. isinstance(povm_layers, (list,tuple)):
for i, layerop in enumerate(povm_layers):
model.povm_blks['layers'][_Label("M%d" % i)] = layerop
def _init_spam_layers(self, prep_layers, povm_layers):
""" Helper function for initializing the .prep_blks and .povm_blks elements of an implicit model"""
# SPAM (same as for cloud noise model)
if prep_layers is None:
pass # no prep layers
elif isinstance(prep_layers, dict):
for rhoname, layerop in prep_layers.items():
self.prep_blks['layers'][_Label(rhoname)] = layerop
elif isinstance(prep_layers, _op.LinearOperator): # just a single layer op
self.prep_blks['layers'][_Label('rho0')] = prep_layers
else: # assume prep_layers is an iterable of layers, e.g. isinstance(prep_layers, (list,tuple)):
for i, layerop in enumerate(prep_layers):
self.prep_blks['layers'][_Label("rho%d" % i)] = layerop

if povm_layers is None:
pass # no povms
elif isinstance(povm_layers, _povm.POVM): # just a single povm - must precede 'dict' test!
self.povm_blks['layers'][_Label('Mdefault')] = povm_layers
elif isinstance(povm_layers, dict):
for povmname, layerop in povm_layers.items():
self.povm_blks['layers'][_Label(povmname)] = layerop
else: # assume povm_layers is an iterable of layers, e.g. isinstance(povm_layers, (list,tuple)):
for i, layerop in enumerate(povm_layers):
self.povm_blks['layers'][_Label("M%d" % i)] = layerop
Loading
Loading