Esempio n. 1
0
    def __init__(self, state_space, target_labels, operation_to_embed, allocated_to_parent=None):
        self.target_labels = tuple(target_labels) if (target_labels is not None) else None
        self.embedded_op = operation_to_embed
        self._iter_elements_cache = {"Hilbert": None, "HilbertSchmidt": None}  # speeds up _iter_matrix_elements

        assert(_StateSpace.cast(state_space).contains_labels(target_labels)), \
            "`target_labels` (%s) not found in `state_space` (%s)" % (str(target_labels), str(state_space))

        evotype = operation_to_embed._evotype

        #Create representation
        #Create representation object
        rep_type_order = ('dense', 'embedded') if evotype.prefer_dense_reps else ('embedded', 'dense')
        rep = None
        for rep_type in rep_type_order:
            try:
                if rep_type == 'embedded':
                    rep = evotype.create_embedded_rep(state_space, self.target_labels, self.embedded_op._rep)
                elif rep_type == 'dense':
                    rep = evotype.create_dense_superop_rep(None, state_space)
                else:
                    assert(False), "Logic error!"

                self._rep_type = rep_type
                break

            except AttributeError:
                pass  # just go to the next rep_type

        if rep is None:
            raise ValueError("Unable to construct representation with evotype: %s" % str(evotype))

        _LinearOperator.__init__(self, rep, evotype)
        self.init_gpindices(allocated_to_parent)  # initialize our gpindices based on sub-members
        if self._rep_type == 'dense': self._update_denserep()
Esempio n. 2
0
    def __init__(self, mx, basis, evotype, state_space):
        """ Initialize a new LinearOperator """
        mx = _LinearOperator.convert_to_matrix(mx)
        state_space = _statespace.default_space_for_udim(mx.shape[0]) if (state_space is None) \
            else _statespace.StateSpace.cast(state_space)
        basis = _Basis.cast(
            basis,
            state_space.dim)  # basis for Hilbert-Schmidt (superop) space
        evotype = _Evotype.cast(evotype)

        #Try to create a dense unitary rep.  If this fails, see if a dense superop rep
        # can be created, as this type of rep can also hold arbitrary unitary ops.
        try:
            rep = evotype.create_dense_unitary_rep(mx, basis, state_space)
            self._reptype = 'unitary'
            self._unitary = None
        except Exception:
            if mx.shape[0] == basis.dim and _np.linalg.norm(mx.imag) < 1e-10:
                # Special case when a *superop* was provided instead of a unitary mx
                superop_mx = mx.real  # used as a convenience case that really shouldn't be used
            else:
                superop_mx = _ot.unitary_to_superop(mx, basis)
            rep = evotype.create_dense_superop_rep(superop_mx, state_space)
            self._reptype = 'superop'
            self._unitary = mx
        self._basis = basis

        _LinearOperator.__init__(self, rep, evotype)
        DenseOperatorInterface.__init__(self)
Esempio n. 3
0
    def __init__(self,
                 state_space,
                 basis="PP",
                 evotype="default",
                 initial_rates=None,
                 seed_or_state=None):
        state_space = _statespace.StateSpace.cast(state_space)
        self.basis = _Basis.cast(basis, state_space.dim, sparse=False)
        assert (
            state_space.dim == self.basis.dim
        ), "Dimension of `basis` must match the dimension (`dim`) of this op."

        evotype = _Evotype.cast(evotype)

        #Setup initial parameters
        self.params = _np.zeros(
            self.basis.size - 1,
            'd')  # note that basis.dim can be < self.dim (OK)
        if initial_rates is not None:
            assert(len(initial_rates) == self.basis.size - 1), \
                "Expected %d initial rates but got %d!" % (self.basis.size - 1, len(initial_rates))
            self.params[:] = self._rates_to_params(initial_rates)
            rates = _np.array(initial_rates)
        else:
            rates = _np.zeros(len(self.params), 'd')

        rep = evotype.create_stochastic_rep(self.basis,
                                            self._get_rate_poly_dicts(), rates,
                                            seed_or_state, state_space)
        _LinearOperator.__init__(self, rep, evotype)
        self._update_rep()  # initialize self._rep
        self._paramlbls = _np.array(
            ['sqrt(%s error rate)' % bl for bl in self.basis.labels[1:]],
            dtype=object)
Esempio n. 4
0
 def __init__(self, mx, evotype, state_space=None):
     """ Initialize a new LinearOperator """
     mx = _LinearOperator.convert_to_matrix(mx)
     state_space = _statespace.default_space_for_dim(mx.shape[0]) if (state_space is None) \
         else _statespace.StateSpace.cast(state_space)
     evotype = _Evotype.cast(evotype)
     rep = evotype.create_dense_superop_rep(mx, state_space)
     _LinearOperator.__init__(self, rep, evotype)
     DenseOperatorInterface.__init__(self)
Esempio n. 5
0
    def __init__(self, op_to_repeat, num_repetitions, evotype="auto"):
        #We may not actually need to save these, since they can be inferred easily
        self.repeated_op = op_to_repeat
        self.num_repetitions = num_repetitions

        state_space = op_to_repeat.state_space

        if evotype == "auto":
            evotype = op_to_repeat._evotype
        evotype = _Evotype.cast(evotype)
        rep = evotype.create_repeated_rep(self.repeated_op._rep,
                                          self.num_repetitions, state_space)
        _LinearOperator.__init__(self, rep, evotype)
        self.init_gpindices()  # initialize our gpindices based on sub-members
Esempio n. 6
0
    def __init__(self, errorgen):
        # Extract superop dimension from 'errorgen'
        state_space = errorgen.state_space
        self.errorgen = errorgen  # don't copy (allow object reuse)

        evotype = self.errorgen._evotype

        #Create representation object
        rep_type_order = ('dense',
                          'experrgen') if evotype.prefer_dense_reps else (
                              'experrgen', 'dense')
        rep = None
        for rep_type in rep_type_order:
            try:
                if rep_type == 'experrgen':
                    # "sparse mode" => don't ever compute matrix-exponential explicitly
                    rep = evotype.create_experrorgen_rep(self.errorgen._rep)
                elif rep_type == 'dense':
                    rep = evotype.create_dense_superop_rep(None, state_space)

                    # Cache values - for later work with dense rep
                    self.exp_err_gen = None  # used for dense_rep=True mode to cache qty needed in deriv_wrt_params
                    self.base_deriv = None
                    self.base_hessian = None
                else:
                    assert (False), "Logic error!"

                self._rep_type = rep_type
                break

            except AttributeError:
                pass  # just go to the next rep_type

        if rep is None:
            raise ValueError(
                "Unable to construct representation with evotype: %s" %
                str(evotype))

        # Caches in case terms are used
        self.terms = {}
        self.exp_terms_cache = {
        }  # used for repeated calls to the exponentiate_terms function
        self.local_term_poly_coeffs = {}

        _LinearOperator.__init__(self, rep, evotype)
        _ErrorGeneratorContainer.__init__(self, self.errorgen)
        self.init_gpindices()  # initialize our gpindices based on sub-members
        self._update_rep()  # updates self._rep
Esempio n. 7
0
    def set_dense(self, m):
        """
        Set the dense-matrix value of this operation.

        Attempts to modify operation parameters so that the specified raw
        operation matrix becomes mx.  Will raise ValueError if this operation
        is not possible.

        Parameters
        ----------
        m : array_like or LinearOperator
            An array of shape (dim, dim) or LinearOperator representing the operation action.

        Returns
        -------
        None
        """
        mx = _LinearOperator.convert_to_matrix(m)
        udim = self.state_space.udim  # maybe create a self.udim?
        if (mx.shape != (udim, udim)):
            raise ValueError("Argument must be a (%d,%d) matrix!" %
                             (udim, udim))
        self._ptr[:, :] = _np.array(mx)
        self._ptr_has_changed()
        self.dirty = True
Esempio n. 8
0
    def set_dense(self, m):
        """
        Set the dense-matrix value of this operation.

        Attempts to modify operation parameters so that the specified raw
        operation matrix becomes mx.  Will raise ValueError if this operation
        is not possible.

        Parameters
        ----------
        m : array_like or LinearOperator
            An array of shape (dim, dim) or LinearOperator representing the operation action.

        Returns
        -------
        None
        """
        mx = _LinearOperator.convert_to_matrix(m)
        if (mx.shape != (self.dim, self.dim)):
            raise ValueError("Argument must be a (%d,%d) matrix!" %
                             (self.dim, self.dim))
        if not (_np.isclose(mx[0, 0], 1.0) and _np.allclose(mx[0, 1:], 0.0)):
            raise ValueError("Cannot set FullTPOp: "
                             "invalid form for 1st row!")
            #For further debugging:  + "\n".join([str(e) for e in mx[0,:]])
        self._ptr[1:, :] = mx[1:, :]
        self._ptr_has_changed()
        self.dirty = True
Esempio n. 9
0
    def __init__(self, m, evotype="default", state_space=None):
        """
        Initialize a FullTPOp object.

        Parameters
        ----------
        m : array_like or LinearOperator
            a square 2D numpy array representing the operation action.  The
            shape of this array sets the dimension of the operation.
        """
        #LinearOperator.__init__(self, LinearOperator.convert_to_matrix(m))
        mx = _LinearOperator.convert_to_matrix(m)
        assert (_np.isrealobj(mx)), "FullTPOp must have *real* values!"
        if not (_np.isclose(mx[0, 0], 1.0) and _np.allclose(mx[0, 1:], 0.0)):
            raise ValueError("Cannot create FullTPOp: "
                             "invalid form for 1st row!")
        _DenseOperator.__init__(self, mx, evotype, state_space)
        assert (self._rep.base.flags['C_CONTIGUOUS']
                and self._rep.base.flags['OWNDATA'])
        assert (isinstance(self._ptr, _ProtectedArray))
        self._paramlbls = _np.array([
            "MxElement %d,%d" % (i, j) for i in range(1, self.dim)
            for j in range(self.dim)
        ],
                                    dtype=object)
Esempio n. 10
0
    def set_dense(self, m):
        """
        Set the dense-matrix value of this operation.

        Attempts to modify operation parameters so that the specified raw
        operation matrix becomes mx.  Will raise ValueError if this operation
        is not possible.

        Parameters
        ----------
        m : array_like or LinearOperator
            An array of shape (dim, dim) or LinearOperator representing the operation action.

        Returns
        -------
        None
        """
        mx = _LinearOperator.convert_to_matrix(m)
        errgen_cls = self.errorgen.__class__

        #Note: this only really works for LindbladErrorGen objects now... make more general in FUTURE?
        truncate = TODENSE_TRUNCATE  # can't just be 'True' since we need to throw errors when appropriate
        new_errgen = errgen_cls.from_operation_matrix_and_blocks(
            mx, self.errorgen.coefficient_blocks, 'auto',
            self.errorgen.matrix_basis, truncate, self.errorgen.evotype,
            self.errorgen.state_space)
        self.errorgen.from_vector(new_errgen.to_vector())
        self._update_rep()  # needed to rebuild exponentiated error gen
        self.dirty = True
Esempio n. 11
0
    def __init__(self, base_matrix, parameter_array, parameter_to_base_indices_map,
                 left_transform=None, right_transform=None, real=False, evotype="default", state_space=None):

        base_matrix = _np.array(_LinearOperator.convert_to_matrix(base_matrix), 'complex')
        #complex, even if passed all real base matrix

        elementExpressions = {}
        for p, ij_tuples in parameter_to_base_indices_map.items():
            for i, j in ij_tuples:
                assert((i, j) not in elementExpressions)  # only one parameter allowed per base index pair
                elementExpressions[(i, j)] = [LinearlyParameterizedElementTerm(1.0, [p])]

        typ = "d" if real else "complex"
        mx = _np.empty(base_matrix.shape, typ)
        self.baseMatrix = base_matrix
        self.parameterArray = parameter_array
        self.numParams = len(parameter_array)
        self.elementExpressions = elementExpressions
        assert(_np.isrealobj(self.parameterArray)), "Parameter array must be real-valued!"

        I = _np.identity(self.baseMatrix.shape[0], 'd')  # LinearlyParameterizedGates are currently assumed to be real
        self.leftTrans = left_transform if (left_transform is not None) else I
        self.rightTrans = right_transform if (right_transform is not None) else I
        self.enforceReal = real

        #Note: dense op reps *always* own their own data so setting writeable flag is OK
        _DenseOperator.__init__(self, mx, evotype, state_space)
        self._ptr.flags.writeable = False  # only _construct_matrix can change array
        self._construct_matrix()  # construct base from the parameters
Esempio n. 12
0
    def __init__(self, ops_to_compose, evotype="auto", state_space="auto", allocated_to_parent=None):
        assert(len(ops_to_compose) > 0 or state_space != "auto"), \
            "Must compose at least one operation when state_space='auto'!"
        self.factorops = list(ops_to_compose)

        if state_space == "auto":
            state_space = ops_to_compose[0].state_space
        else:
            state_space = _statespace.StateSpace.cast(state_space)
        assert(all([state_space.is_compatible_with(operation.state_space) for operation in ops_to_compose])), \
            "All operations must have compatible state spaces (%s expected)!" % str(state_space)

        if evotype == "auto":
            evotype = ops_to_compose[0]._evotype
        assert(all([evotype == operation._evotype for operation in ops_to_compose])), \
            "All operations must have the same evolution type (%s expected)!" % evotype
        evotype = _Evotype.cast(evotype)

        #Create representation object
        rep_type_order = ('dense', 'composed') if evotype.prefer_dense_reps else ('composed', 'dense')
        rep = None
        for rep_type in rep_type_order:
            try:
                if rep_type == 'composed':
                    factor_op_reps = [op._rep for op in self.factorops]
                    rep = evotype.create_composed_rep(factor_op_reps, state_space)
                elif rep_type == 'dense':
                    rep = evotype.create_dense_superop_rep(None, state_space)
                else:
                    assert(False), "Logic error!"

                self._rep_type = rep_type
                break

            except AttributeError:
                pass  # just go to the next rep_type

        if rep is None:
            raise ValueError("Unable to construct representation with evotype: %s" % str(evotype))

        # caches in case terms are used
        self.terms = {}
        self.local_term_poly_coeffs = {}

        _LinearOperator.__init__(self, rep, evotype)
        self.init_gpindices(allocated_to_parent)  # initialize our gpindices based on sub-members
        if self._rep_type == 'dense': self._update_denserep()  # update dense rep if needed
Esempio n. 13
0
    def __init__(self,
                 unitary,
                 symplecticrep=None,
                 basis='pp',
                 evotype='default',
                 state_space=None):
        self.unitary = unitary
        assert (self.unitary is not None), "Must supply `unitary` argument!"
        U = self.unitary.to_dense() if isinstance(
            self.unitary, _LinearOperator) else self.unitary

        # Make contiguous for Cython-based evotypes
        U = _np.ascontiguousarray(U, dtype=complex)

        state_space = _statespace.default_space_for_udim(U.shape[0]) if (state_space is None) \
            else _statespace.StateSpace.cast(state_space)

        evotype = _Evotype.cast(evotype)
        rep = evotype.create_clifford_rep(U, symplecticrep, basis, state_space)
        _LinearOperator.__init__(self, rep, evotype)
Esempio n. 14
0
    def quick_init(cls, unitary_mx, superop_mx, basis, evotype, state_space):
        # mx must be a numpy array for a unitary operator
        # state_space as StateSpace
        # evotyp an Evotype
        # basis a Basis
        self = cls.__new__(cls)
        try:
            rep = evotype.create_dense_unitary_rep(unitary_mx, basis,
                                                   state_space)
            self._reptype = 'unitary'
            self._unitary = None
        except Exception:
            rep = evotype.create_dense_superop_rep(superop_mx, state_space)
            self._reptype = 'superop'
            self._unitary = unitary_mx

        self._basis = basis
        _LinearOperator.__init__(self, rep, evotype)
        DenseOperatorInterface.__init__(self)
        return self
Esempio n. 15
0
    def __init__(self, errgens_to_compose, evotype="auto", state_space="auto"):
        assert(len(errgens_to_compose) > 0 or state_space != "auto"), \
            "Must compose at least one error generator when state_space='auto'!"
        self.factors = errgens_to_compose

        if state_space == "auto":
            state_space = errgens_to_compose[0].state_space
        else:
            state_space = _statespace.StateSpace.cast(state_space)

        assert(all([state_space.is_compatible_with(eg.state_space) for eg in errgens_to_compose])), \
            "All error generators must have compatible state spaces (%s expected)!" % str(state_space)

        if evotype == "auto":
            evotype = errgens_to_compose[0]._evotype
        evotype = _Evotype.cast(evotype)
        assert(all([evotype == eg._evotype for eg in errgens_to_compose])), \
            "All error generators must have the same evolution type (%s expected)!" % evotype

        # set "API" error-generator members (to interface properly w/other objects)
        # FUTURE: create a base class that defines this interface (maybe w/properties?)
        #self.sparse = errgens_to_compose[0].sparse \
        #    if len(errgens_to_compose) > 0 else False
        #assert(all([self.sparse == eg.sparse for eg in errgens_to_compose])), \
        #    "All error generators must have the same sparsity (%s expected)!" % self.sparse

        self.matrix_basis = errgens_to_compose[0].matrix_basis \
            if len(errgens_to_compose) > 0 else None
        assert(all([self.matrix_basis.is_equivalent(eg.matrix_basis, sparseness_must_match=False)
                    for eg in errgens_to_compose])), \
            "All error generators must have the same matrix basis (%s expected)!" % str(self.matrix_basis)

        #Create representation object
        factor_reps = [op._rep for op in self.factors]
        rep = evotype.create_sum_rep(factor_reps, state_space)

        _LinearOperator.__init__(self, rep, evotype)
        self.init_gpindices()  # initialize our gpindices based on sub-members