def build_gate(): mx = np.identity(4, 'd') mx2 = np.array( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, -1, 0]], 'd') evotype = 'default' state_space = None # constructs a default based on size of mx gate = op.ComposedOp([ op.StaticArbitraryOp(mx, evotype, state_space), op.FullArbitraryOp(mx, evotype, state_space), op.FullArbitraryOp(mx2, evotype, state_space), op.StaticArbitraryOp(mx, evotype, state_space), op.FullArbitraryOp(mx2, evotype, state_space) ]) # TODO does this need to be done? dummyGS = ExplicitOpModel(['Q0']) dummyGS.operations['Gcomp'] = gate # so to/from vector works dummyGS.to_vector() return gate
def __init__(self, operation): """ Create a new element based on `operation` Parameters ---------- operation : LinearOperator The operation to base this element on. It provides both parameterization information and the gauge transformation matrix itself. """ if not isinstance(operation, _op.LinearOperator): operation = _op.StaticArbitraryOp(operation, evotype='default', state_space=None) self._operation = operation self._inv_matrix = None GaugeGroupElement.__init__(self)
def __init__(self, operation, elementcls, name): """ Create a new `OpGaugeGroup`. Parameters ---------- operation : LinearOperator The LinearOperator to base this Gauge group on. elementcls : class The element class to use when implementing the `compute_element` method. name : str A name for this group - used for reporting what type of gauge optimization was performed. """ if not isinstance(operation, _op.LinearOperator): operation = _op.StaticArbitraryOp(operation, evotype='default', state_space=None) self._operation = operation self.element = elementcls GaugeGroup.__init__(self, name)
def test_explicit_model_comparisons(self): ex_mdl1 = smq2Q_XYICNOT.target_model() ex_mmg1 = ex_mdl1.create_modelmember_graph() # Copy, should be similar and equivalent ex_mdl2 = ex_mdl1.copy() ex_mmg2 = ex_mdl2.create_modelmember_graph() self.assertTrue(ex_mmg2.is_similar(ex_mmg1)) self.assertTrue(ex_mmg2.is_equivalent(ex_mmg1)) # Change parameter, similar but not equivalent ex_mdl3 = ex_mdl1.copy() ex_mdl3.operations['Gxpi2', 0][0, 0] = 0.0 ex_mmg3 = ex_mdl3.create_modelmember_graph() self.assertTrue(ex_mmg3.is_similar(ex_mmg1)) self.assertFalse(ex_mmg3.is_equivalent(ex_mmg1)) # Change parameterization, not similar or equivalent ex_mdl4 = ex_mdl1.copy() ex_mdl4.operations['Gxpi2', 0] = _op.StaticArbitraryOp( ex_mdl4.operations['Gxpi2', 0]) ex_mmg4 = ex_mdl4.create_modelmember_graph() self.assertFalse(ex_mmg4.is_similar(ex_mmg1)) self.assertFalse(ex_mmg4.is_equivalent(ex_mmg1))
def __init__(self, processor_spec, gatedict, prep_layers=None, povm_layers=None, build_cloudnoise_fn=None, build_cloudkey_fn=None, simulator="map", evotype="default", errcomp_type="gates", implicit_idle_mode="none", verbosity=0): qudit_labels = processor_spec.qudit_labels state_space = _statespace.QubitSpace(qudit_labels) if isinstance(processor_spec, _QubitProcessorSpec) \ else _statespace.QuditSpace(qudit_labels, processor_spec.qudit_udims) simulator = _FSim.cast( simulator, state_space.num_qubits if isinstance( state_space, _statespace.QubitSpace) else None) prefer_dense_reps = isinstance(simulator, _MatrixFSim) evotype = _Evotype.cast(evotype, default_prefer_dense_reps=prefer_dense_reps) # Build gate dictionaries. A value of `gatedict` can be an array, a LinearOperator, or an OpFactory. # For later processing, we'll create mm_gatedict to contain each item as a ModelMember. For cloud- # noise models, these gate operations should be *static* (no parameters) as they represent the target # operations and all noise (and parameters) are assumed to enter through the cloudnoise members. mm_gatedict = _collections.OrderedDict( ) # static *target* ops as ModelMembers for key, gate in gatedict.items(): if isinstance(gate, _op.LinearOperator): assert ( gate.num_params == 0 ), "Only *static* ideal operators are allowed in `gatedict`!" mm_gatedict[key] = gate elif isinstance(gate, _opfactory.OpFactory): assert ( gate.num_params == 0 ), "Only *static* ideal factories are allowed in `gatedict`!" mm_gatedict[key] = gate else: # presumably a numpy array or something like it: mm_gatedict[key] = _op.StaticArbitraryOp( gate, evotype, state_space=None) # use default state space assert(mm_gatedict[key]._evotype == evotype), \ ("Custom gate object supplied in `gatedict` for key %s has evotype %s (!= expected %s)" % (str(key), str(mm_gatedict[key]._evotype), str(evotype))) #Set other members self.processor_spec = processor_spec self.errcomp_type = errcomp_type idle_names = self.processor_spec.idle_gate_names global_idle_name = self.processor_spec.global_idle_gate_name # Set noisy_global_idle_name == global_idle_name if the global idle gate isn't the perfect identity # and if we're generating cloudnoise members (if we're not then layer rules could encouter a key error # if we let noisy_global_idle_name be non-None). global_idle_gate = mm_gatedict.get(global_idle_name, None) if (global_idle_gate is not None) and (build_cloudnoise_fn is not None) \ and (build_cloudnoise_fn(self.processor_spec.global_idle_layer_label) is not None): noisy_global_idle_name = global_idle_name else: noisy_global_idle_name = None singleq_idle_layer_labels = {} for idle_name in idle_names: if self.processor_spec.gate_num_qubits(idle_name) == 1: for idlelayer_sslbls in self.processor_spec.resolved_availability( idle_name, 'tuple'): if idlelayer_sslbls is None: continue # case of 1Q model with "global" idle assert (len(idlelayer_sslbls) == 1 ) # should be a 1-qubit gate! if idlelayer_sslbls not in singleq_idle_layer_labels: singleq_idle_layer_labels[idlelayer_sslbls] = _Lbl( idle_name, idlelayer_sslbls) #assert(set(idle_names).issubset([global_idle_name])), \ # "Only global idle operations are allowed in a CloudNoiseModel!" layer_rules = CloudNoiseLayerRules(errcomp_type, qudit_labels, implicit_idle_mode, singleq_idle_layer_labels, noisy_global_idle_name) super(CloudNoiseModel, self).__init__(state_space, layer_rules, "pp", simulator=simulator, evotype=evotype) flags = { 'auto_embed': False, 'match_parent_statespace': False, 'match_parent_evotype': True, 'cast_to_type': None } self.prep_blks['layers'] = _OrderedMemberDict(self, None, None, flags) self.povm_blks['layers'] = _OrderedMemberDict(self, None, None, flags) self.operation_blks['gates'] = _OrderedMemberDict( self, None, None, flags) self.operation_blks['cloudnoise'] = _OrderedMemberDict( self, None, None, flags) self.operation_blks['layers'] = _OrderedMemberDict( self, None, None, flags) self.instrument_blks['layers'] = _OrderedMemberDict( self, None, None, flags) self.factories['gates'] = _OrderedMemberDict(self, None, None, flags) self.factories['cloudnoise'] = _OrderedMemberDict( self, None, None, flags) self.factories['layers'] = _OrderedMemberDict(self, None, None, flags) printer = _VerbosityPrinter.create_printer(verbosity) printer.log("Creating a %d-qudit cloud-noise model" % self.processor_spec.num_qudits) # a dictionary of "cloud" objects # keys = cloud identifiers, e.g. (target_qudit_indices, cloud_qudit_indices) tuples # values = list of gate-labels giving the gates (primitive layers?) associated with that cloud (necessary?) self._clouds = _collections.OrderedDict() for gn in self.processor_spec.gate_names: # process gate names (no sslbls, e.g. "Gx", not "Gx:0") - we'll check for the # latter when we process the corresponding gate name's availability gate_unitary = self.processor_spec.gate_unitaries[gn] resolved_avail = self.processor_spec.resolved_availability(gn) gate = mm_gatedict.get( gn, None ) # a static op or factory, no need to consider if "independent" (no params) gate_is_factory = callable(gate_unitary) or isinstance( gate, _opfactory.OpFactory) #gate_is_noiseless_identity = (gate is None) or \ # (isinstance(gate, _op.ComposedOp) and len(gate.factorops) == 0) if gate is not None: # (a gate name may not be in gatedict if it's an identity without any noise) if gate_is_factory: self.factories['gates'][_Lbl(gn)] = gate else: self.operation_blks['gates'][_Lbl(gn)] = gate if callable(resolved_avail) or resolved_avail == '*': # Target operation if gate is not None: allowed_sslbls_fn = resolved_avail if callable( resolved_avail) else None gate_nQudits = self.processor_spec.gate_num_qudits(gn) printer.log("Creating %dQ %s gate on arbitrary qudits!!" % (gate_nQudits, gn)) self.factories['layers'][_Lbl( gn)] = _opfactory.EmbeddingOpFactory( state_space, gate, num_target_labels=gate_nQudits, allowed_sslbls_fn=allowed_sslbls_fn) # add any primitive ops for this embedding factory? # Cloudnoise operation if build_cloudnoise_fn is not None: cloudnoise = build_cloudnoise_fn(_Lbl(gn)) if cloudnoise is not None: # build function can return None to signify no noise assert (isinstance(cloudnoise, _opfactory.EmbeddingOpFactory)), \ ("`build_cloudnoise_fn` must return an EmbeddingOpFactory for gate %s" " with arbitrary availability") % gn self.factories['cloudnoise'][_Lbl(gn)] = cloudnoise else: # resolved_avail is a list/tuple of available sslbls for the current gate/factory for inds in resolved_avail: # inds are target qudit labels #Target operation if gate is not None: printer.log("Creating %dQ %s gate on qudits %s!!" % ((len(qudit_labels) if inds is None else len(inds)), gn, inds)) assert(inds is None or _Lbl(gn, inds) not in gatedict), \ ("Cloudnoise models do not accept primitive-op labels, e.g. %s, in `gatedict` as this dict " "specfies the ideal target gates. Perhaps make the cloudnoise depend on the target qudits " "of the %s gate?") % (str(_Lbl(gn, inds)), gn) if gate_is_factory: self.factories['layers'][_Lbl(gn, inds)] = gate if (inds is None) else \ _opfactory.EmbeddedOpFactory(state_space, inds, gate) # add any primitive ops for this factory? else: self.operation_blks['layers'][_Lbl(gn, inds)] = gate if (inds is None) else \ _op.EmbeddedOp(state_space, inds, gate) #Cloudnoise operation if build_cloudnoise_fn is not None: cloudnoise = build_cloudnoise_fn(_Lbl(gn, inds)) if cloudnoise is not None: # build function can return None to signify no noise if isinstance(cloudnoise, _opfactory.OpFactory): self.factories['cloudnoise'][_Lbl( gn, inds)] = cloudnoise else: self.operation_blks['cloudnoise'][_Lbl( gn, inds)] = cloudnoise if build_cloudkey_fn is not None: # TODO: is there any way to get a default "key", e.g. the # qudits touched by the corresponding cloudnoise op? # need a way to identify a clound (e.g. Gx and Gy gates on some qudit will have *same* cloud) cloud_key = build_cloudkey_fn(_Lbl(gn, inds)) if cloud_key not in self.clouds: self.clouds[cloud_key] = [] self.clouds[cloud_key].append(_Lbl(gn, inds)) #keep track of the primitive-layer labels in each cloud, # 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 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(): printer.log(" %s: %s" % (op_blk_lbl, ', '.join(map(str, op_blk.keys())))) self._clean_paramvec()
def __init__(self, processor_spec, gatedict, prep_layers=None, povm_layers=None, evotype="default", simulator="auto", on_construction_error='raise', independent_gates=False, ensure_composed_gates=False, implicit_idle_mode="none"): qudit_labels = processor_spec.qudit_labels state_space = _statespace.QubitSpace(qudit_labels) if isinstance(processor_spec, _QubitProcessorSpec) \ else _statespace.QuditSpace(qudit_labels, processor_spec.qudit_udims) simulator = _FSim.cast( simulator, state_space.num_qubits if isinstance( state_space, _statespace.QubitSpace) else None) prefer_dense_reps = isinstance(simulator, _MatrixFSim) evotype = _Evotype.cast(evotype, default_prefer_dense_reps=prefer_dense_reps) # Build gate dictionaries. A value of `gatedict` can be an array, a LinearOperator, or an OpFactory. # For later processing, we'll create mm_gatedict to contain each item as a ModelMember. In local noise # models, these gates can be parameterized however the user desires - the LocalNoiseModel just embeds these # operators appropriately. mm_gatedict = _collections.OrderedDict() # ops as ModelMembers for key, gate in gatedict.items(): if isinstance(gate, (_op.LinearOperator, _opfactory.OpFactory)): mm_gatedict[key] = gate else: # presumably a numpy array or something like it. mm_gatedict[key] = _op.StaticArbitraryOp( gate, evotype, state_space) # static gates by default self.processor_spec = processor_spec idle_names = processor_spec.idle_gate_names global_idle_layer_label = processor_spec.global_idle_layer_label layer_rules = _SimpleCompLayerRules(qudit_labels, implicit_idle_mode, None, global_idle_layer_label) super(LocalNoiseModel, self).__init__(state_space, layer_rules, 'pp', simulator=simulator, evotype=evotype) flags = { 'auto_embed': False, 'match_parent_statespace': False, 'match_parent_evotype': True, 'cast_to_type': None } self.prep_blks['layers'] = _OrderedMemberDict(self, None, None, flags) self.povm_blks['layers'] = _OrderedMemberDict(self, None, None, flags) self.operation_blks['gates'] = _OrderedMemberDict( self, None, None, flags) self.operation_blks['layers'] = _OrderedMemberDict( self, None, None, flags) self.instrument_blks['layers'] = _OrderedMemberDict( self, None, None, flags) self.factories['gates'] = _OrderedMemberDict(self, None, None, flags) self.factories['layers'] = _OrderedMemberDict(self, None, None, flags) _init_spam_layers(self, prep_layers, povm_layers) # SPAM for gateName in self.processor_spec.gate_names: # process gate names (no sslbls, e.g. "Gx", not "Gx:0") - we'll check for the # latter when we process the corresponding gate name's availability gate_unitary = self.processor_spec.gate_unitaries[gateName] resolved_avail = self.processor_spec.resolved_availability( gateName) gate_is_idle = gateName in idle_names gate_is_factory = callable(gate_unitary) if not independent_gates: # then get our "template" gate ready # for non-independent gates, need to specify gate name alone (no sslbls): gate = mm_gatedict.get(gateName, None) gate_is_factory = gate_is_factory or isinstance( gate, _opfactory.OpFactory) if gate is not None: # (a gate name may not be in gatedict if it's an identity without any noise) if ensure_composed_gates and not isinstance( gate, _op.ComposedOp) and not gate_is_factory: #Make a single ComposedOp *here*, which is used # in all the embeddings for different target qudits gate = _op.ComposedOp( [gate], state_space="auto", evotype="auto") # to make adding factors easy if gate_is_factory: self.factories['gates'][_Lbl(gateName)] = gate else: self.operation_blks['gates'][_Lbl(gateName)] = gate if gate_is_idle and gate.state_space.num_qudits == 1 and global_idle_layer_label is None: # then attempt to turn this 1Q idle into a global idle (for implied idle layers) global_idle = _op.ComposedOp([ _op.EmbeddedOp(state_space, (qlbl, ), gate) for qlbl in qudit_labels ]) self.operation_blks['layers'][_Lbl( '{auto_global_idle}')] = global_idle global_idle_layer_label = layer_rules.global_idle_layer_label = _Lbl( '{auto_global_idle}') else: gate = None # this is set to something useful in the "elif independent_gates" block below if callable(resolved_avail) or resolved_avail == '*': # then `gate` has function-determined or arbitrary availability, and we just need to # put it in an EmbeddingOpFactory - no need to copy it or look # for overrides in `gatedict` - there's always just *one* instance # of an arbitrarily available gate or factory. base_gate = mm_gatedict[gateName] # Note: can't use automatic-embedding b/c we need to force embedding # when just ordering doesn't align (e.g. Gcnot:1:0 on 2-qudits needs to embed) allowed_sslbls_fn = resolved_avail if callable( resolved_avail) else None gate_nQudits = self.processor_spec.gate_num_qudits(gateName) embedded_op = _opfactory.EmbeddingOpFactory( state_space, base_gate, num_target_labels=gate_nQudits, allowed_sslbls_fn=allowed_sslbls_fn) self.factories['layers'][_Lbl(gateName)] = embedded_op else: # resolved_avail is a list/tuple of available sslbls for the current gate/factory singleQ_idle_layer_labels = _collections.OrderedDict() for inds in resolved_avail: if _Lbl(gateName, inds) in mm_gatedict and inds is not None: #Allow elements of `gatedict` that *have* sslbls override the # default copy/reference of the "name-only" gate: base_gate = mm_gatedict[_Lbl(gateName, inds)] gate_is_factory = gate_is_factory or isinstance( base_gate, _opfactory.OpFactory) if gate_is_factory: self.factories['gates'][_Lbl(gateName, inds)] = base_gate else: self.operation_blks['gates'][_Lbl( gateName, inds)] = base_gate elif independent_gates: # then we need to ~copy `gate` so it has indep params gate = mm_gatedict.get( gateName, None) # was set to `None` above; reset here gate_is_factory = gate_is_factory or isinstance( gate, _opfactory.OpFactory) if gate is not None: # (may be False if gate is an identity without any noise) if ensure_composed_gates and not gate_is_factory: #Make a single ComposedOp *here*, for *only this* embedding # Don't copy gate here, as we assume it's ok to be shared when we # have independent composed gates base_gate = _op.ComposedOp([gate], evotype="auto", state_space="auto") else: # want independent params but not a composed gate, so .copy() base_gate = gate.copy( ) # so independent parameters if gate_is_factory: self.factories['gates'][_Lbl(gateName, inds)] = base_gate else: self.operation_blks['gates'][_Lbl( gateName, inds)] = base_gate else: # (not independent_gates, so `gate` is set to non-None above) base_gate = gate # already a Composed operator (for easy addition # of factors) if ensure_composed_gates == True and not gate_is_factory if base_gate is None: continue # end loop here if base_gate is just a perfect identity that shouldn't be added #At this point, `base_gate` is the operator or factory that we want to embed into inds # into inds (except in the special case inds[0] == '*' where we make an EmbeddingOpFactory) try: if gate_is_factory: if inds is None or inds == tuple( qudit_labels): # then no need to embed embedded_op = base_gate else: embedded_op = _opfactory.EmbeddedOpFactory( state_space, inds, base_gate) self.factories['layers'][_Lbl(gateName, inds)] = embedded_op else: if inds is None or inds == tuple( qudit_labels): # then no need to embed embedded_op = base_gate else: embedded_op = _op.EmbeddedOp( state_space, inds, base_gate) self.operation_blks['layers'][_Lbl( gateName, inds)] = embedded_op # If a 1Q idle gate (factories not supported yet) then turn this into a global idle if gate_is_idle and base_gate.state_space.num_qubits == 1 \ and global_idle_layer_label is None: singleQ_idle_layer_labels[inds] = _Lbl( gateName, inds) # allow custom setting of this? except Exception as e: if on_construction_error == 'warn': _warnings.warn( "Failed to embed %s gate. Dropping it." % str(_Lbl(gateName, inds))) if on_construction_error in ('warn', 'ignore'): continue else: raise e if len(singleQ_idle_layer_labels) > 0: if implicit_idle_mode == 'add_global' and global_idle_layer_label is None: # then create a global idle based on 1Q idle gates global_idle = _op.ComposedOp([ self.operation_blks['layers'][lbl] for lbl in singleQ_idle_layer_labels.values() ]) global_idle_layer_label = layer_rules.global_idle_layer_label = _Lbl( '{auto_global_idle}') self.operation_blks['layers'][_Lbl( '{auto_global_idle}')] = global_idle elif implicit_idle_mode == 'pad_1Q': layer_rules.single_qubit_idle_layer_labels = singleQ_idle_layer_labels self._clean_paramvec()
def build_povm(self): sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense()) return ComposedPOVM(sdop, self.base_povm, 'pp')
def build_vec(self): sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense()) return ComposedState(self.base_prep_vec, sdop)