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()
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)
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)
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)
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
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
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
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
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)
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
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
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
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)
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
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