Esempio n. 1
0
    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
Esempio n. 2
0
    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)
Esempio n. 3
0
    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)
Esempio n. 4
0
    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))
Esempio n. 5
0
    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()
Esempio n. 6
0
    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()
Esempio n. 7
0
 def build_povm(self):
     sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense())
     return ComposedPOVM(sdop, self.base_povm, 'pp')
Esempio n. 8
0
 def build_vec(self):
     sdop = op.StaticArbitraryOp(self.base_noise_op.to_dense())
     return ComposedState(self.base_prep_vec, sdop)