def _compute_taylor_order_terms(self, order, max_polynomial_vars, gpindices_array): # separated for profiling terms = [] if len(self.factorops) > 0: for p in _lt.partition_into(order, len(self.factorops)): factor_lists = [self.factorops[i].taylor_order_terms(pi, max_polynomial_vars) for i, pi in enumerate(p)] for factors in _itertools.product(*factor_lists): terms.append(_term.compose_terms(factors)) elif order == 0: # special case: ComposedOp with no factors == identity identityTerm = _term.RankOnePolynomialOpTerm.create_from(_Polynomial({(): 1.0}, max_polynomial_vars), None, None, self._evotype, self.state_space) terms.append(identityTerm) self.terms[order] = terms #def _decompose_indices(x): # return tuple(_modelmember._decompose_gpindices( # self.gpindices, _np.array(x, _np.int64))) mapvec = _np.ascontiguousarray(_np.zeros(max_polynomial_vars, _np.int64)) for ii, i in enumerate(gpindices_array): mapvec[i] = ii #poly_coeffs = [t.coeff.map_indices(_decompose_indices) for t in terms] # with *local* indices poly_coeffs = [t.coeff.mapvec_indices(mapvec) for t in terms] # with *local* indices tapes = [poly.compact(complex_coeff_tape=True) for poly in poly_coeffs] if len(tapes) > 0: vtape = _np.concatenate([t[0] for t in tapes]) ctape = _np.concatenate([t[1] for t in tapes]) else: vtape = _np.empty(0, _np.int64) ctape = _np.empty(0, complex) coeffs_as_compact_polys = (vtape, ctape) self.local_term_poly_coeffs[order] = coeffs_as_compact_polys
def _compute_taylor_order_terms( self, order, max_polynomial_vars): # separated for profiling mapvec = _np.ascontiguousarray( _np.zeros(max_polynomial_vars, _np.int64)) for ii, i in enumerate(self.gpindices_as_array()): mapvec[ii] = i def _compose_poly_indices(terms): for term in terms: #term.map_indices_inplace(lambda x: tuple(_modelmember._compose_gpindices( # self.gpindices, _np.array(x, _np.int64)))) term.mapvec_indices_inplace(mapvec) return terms assert (self.gpindices is not None), "LindbladOp must be added to a Model before use!" mpv = max_polynomial_vars #Note: for now, *all* of an error generator's terms are considered 0-th order, # so the below call to taylor_order_terms just gets all of them. In the FUTURE # we might want to allow a distinction among the error generator terms, in which # case this term-exponentiation step will need to become more complicated... postTerm = _term.RankOnePolynomialOpTerm.create_from( _Polynomial({(): 1.0}, mpv), None, None, self._evotype, self.state_space) # identity loc_terms = _term.exponentiate_terms( self.errorgen.taylor_order_terms(0, max_polynomial_vars), order, postTerm, self.exp_terms_cache) #OLD: loc_terms = [ t.collapse() for t in loc_terms ] # collapse terms for speed poly_coeffs = [t.coeff for t in loc_terms] tapes = [poly.compact(complex_coeff_tape=True) for poly in poly_coeffs] if len(tapes) > 0: vtape = _np.concatenate([t[0] for t in tapes]) ctape = _np.concatenate([t[1] for t in tapes]) else: vtape = _np.empty(0, _np.int64) ctape = _np.empty(0, complex) coeffs_as_compact_polys = (vtape, ctape) self.local_term_poly_coeffs[order] = coeffs_as_compact_polys # only cache terms with *global* indices to avoid confusion... self.terms[order] = _compose_poly_indices(loc_terms)
def taylor_order_terms(self, order, max_polynomial_vars=100, return_coeff_polys=False): """ Get the `order`-th order Taylor-expansion terms of this state vector. This function either constructs or returns a cached list of the terms at the given order. Each term is "rank-1", meaning that it is a state preparation followed by or POVM effect preceded by actions on a density matrix `rho` of the form: `rho -> A rho B` The coefficients of these terms are typically polynomials of the State's parameters, where the polynomial's variable indices index the *global* parameters of the State's parent (usually a :class:`Model`) , not the State's local parameter array (i.e. that returned from `to_vector`). Parameters ---------- order : int The order of terms to get. max_polynomial_vars : int, optional maximum number of variables the created polynomials can have. return_coeff_polys : bool Whether a parallel list of locally-indexed (using variable indices corresponding to *this* object's parameters rather than its parent's) polynomial coefficients should be returned as well. Returns ------- terms : list A list of :class:`RankOneTerm` objects. coefficients : list Only present when `return_coeff_polys == True`. A list of *compact* polynomial objects, meaning that each element is a `(vtape,ctape)` 2-tuple formed by concatenating together the output of :method:`Polynomial.compact`. """ if order == 0: # only 0-th order term exists (assumes static pure_state_vec) coeff = _Polynomial({(): 1.0}, max_polynomial_vars) #if self._prep_or_effect == "prep": terms = [_term.RankOnePolynomialPrepTerm.create_from(coeff, self, self, self._evotype, self.state_space)] #else: # terms = [_term.RankOnePolynomialEffectTerm.create_from(coeff, purevec, purevec, # self._evotype, self.state_space)] if return_coeff_polys: coeffs_as_compact_polys = coeff.compact(complex_coeff_tape=True) return terms, coeffs_as_compact_polys else: return terms else: if return_coeff_polys: vtape = _np.empty(0, _np.int64) ctape = _np.empty(0, complex) return [], (vtape, ctape) else: return []
def taylor_order_terms(self, order, max_polynomial_vars=100, return_coeff_polys=False): """ Get the `order`-th order Taylor-expansion terms of this operation. This function either constructs or returns a cached list of the terms at the given order. Each term is "rank-1", meaning that its action on a density matrix `rho` can be written: `rho -> A rho B` The coefficients of these terms are typically polynomials of the operation's parameters, where the polynomial's variable indices index the *global* parameters of the operation's parent (usually a :class:`Model`), not the operation's local parameter array (i.e. that returned from `to_vector`). Parameters ---------- order : int Which order terms (in a Taylor expansion of this :class:`LindbladOp`) to retrieve. max_polynomial_vars : int, optional maximum number of variables the created polynomials can have. return_coeff_polys : bool Whether a parallel list of locally-indexed (using variable indices corresponding to *this* object's parameters rather than its parent's) polynomial coefficients should be returned as well. Returns ------- terms : list A list of :class:`RankOneTerm` objects. coefficients : list Only present when `return_coeff_polys == True`. A list of *compact* polynomial objects, meaning that each element is a `(vtape,ctape)` 2-tuple formed by concatenating together the output of :method:`Polynomial.compact`. """ #Same as unitary op -- assume this op acts as a single unitary term -- consolidate in FUTURE? if order == 0: # only 0-th order term exists coeff = _Polynomial({(): 1.0}, max_polynomial_vars) terms = [ _term.RankOnePolynomialOpTerm.create_from( coeff, self, self, self._evotype, self.state_space) ] if return_coeff_polys: coeffs_as_compact_polys = coeff.compact( complex_coeff_tape=True) return terms, coeffs_as_compact_polys else: return terms else: if return_coeff_polys: vtape = _np.empty(0, _np.int64) ctape = _np.empty(0, complex) return [], (vtape, ctape) else: return []
def taylor_order_terms_above_mag(self, order, max_polynomial_vars, min_term_mag): """ Get the `order`-th order Taylor-expansion terms of this operation that have magnitude above `min_term_mag`. This function constructs the terms at the given order which have a magnitude (given by the absolute value of their coefficient) that is greater than or equal to `min_term_mag`. It calls :method:`taylor_order_terms` internally, so that all the terms at order `order` are typically cached for future calls. The coefficients of these terms are typically polynomials of the operation's parameters, where the polynomial's variable indices index the *global* parameters of the operation's parent (usually a :class:`Model`), not the operation's local parameter array (i.e. that returned from `to_vector`). Parameters ---------- order : int The order of terms to get (and filter). max_polynomial_vars : int, optional maximum number of variables the created polynomials can have. min_term_mag : float the minimum term magnitude. Returns ------- list A list of :class:`Rank1Term` objects. """ mapvec = _np.ascontiguousarray( _np.zeros(max_polynomial_vars, _np.int64)) for ii, i in enumerate(self.gpindices_as_array()): mapvec[ii] = i assert (self.gpindices is not None), "LindbladOp must be added to a Model before use!" mpv = max_polynomial_vars postTerm = _term.RankOnePolynomialOpTerm.create_from( _Polynomial({(): 1.0}, mpv), None, None, self._evotype, self.state_space) # identity term postTerm = postTerm.copy_with_magnitude(1.0) #Note: for now, *all* of an error generator's terms are considered 0-th order, # so the below call to taylor_order_terms just gets all of them. In the FUTURE # we might want to allow a distinction among the error generator terms, in which # case this term-exponentiation step will need to become more complicated... errgen_terms = self.errorgen.taylor_order_terms(0, max_polynomial_vars) #DEBUG CHECK MAGS OF ERRGEN COEFFS #poly_coeffs = [t.coeff for t in errgen_terms] #tapes = [poly.compact(complex_coeff_tape=True) for poly in poly_coeffs] #if len(tapes) > 0: # vtape = _np.concatenate([t[0] for t in tapes]) # ctape = _np.concatenate([t[1] for t in tapes]) #else: # vtape = _np.empty(0, _np.int64) # ctape = _np.empty(0, complex) #v = self.to_vector() #errgen_coeffs = _bulk_eval_compact_polynomials_complex( # vtape, ctape, v, (len(errgen_terms),)) # an array of coeffs #for coeff, t in zip(errgen_coeffs, errgen_terms): # coeff2 = t.coeff.evaluate(v) # if not _np.isclose(coeff,coeff2): # assert(False), "STOP" # t.set_magnitude(abs(coeff)) #evaluate errgen_terms' coefficients using their local vector of parameters # (which happends to be the same as our paramvec in this case) egvec = self.errorgen.to_vector( ) # we need errorgen's vector (usually not in rep) to perform evaluation errgen_terms = [ egt.copy_with_magnitude(abs(egt.coeff.evaluate(egvec))) for egt in errgen_terms ] terms = [] for term in _term.exponentiate_terms_above_mag( errgen_terms, order, postTerm, min_term_mag=min_term_mag): #poly_coeff = term.coeff #compact_poly_coeff = poly_coeff.compact(complex_coeff_tape=True) term.mapvec_indices_inplace(mapvec) # local -> global indices # DEBUG CHECK - to ensure term magnitudes are being set correctly (i.e. are in sync with evaluated coeffs) # t = term # vt, ct = t._rep.coeff.compact_complex() # coeff_array = _bulk_eval_compact_polynomials_complex(vt, ct, self.parent.to_vector(), (1,)) # if not _np.isclose(abs(coeff_array[0]), t._rep.magnitude): # DEBUG!!! # print(coeff_array[0], "vs.", t._rep.magnitude) # import bpdb; bpdb.set_trace() # c1 = _Polynomial.from_rep(t._rep.coeff) terms.append(term) return terms
def taylor_order_terms(self, order, max_polynomial_vars=100, return_coeff_polys=False): """ Get the `order`-th order Taylor-expansion terms of this operation. This function either constructs or returns a cached list of the terms at the given order. Each term is "rank-1", meaning that its action on a density matrix `rho` can be written: `rho -> A rho B` The coefficients of these terms are typically polynomials of the operation's parameters, where the polynomial's variable indices index the *global* parameters of the operation's parent (usually a :class:`Model`), not the operation's local parameter array (i.e. that returned from `to_vector`). Parameters ---------- order : int Which order terms (in a Taylor expansion of this :class:`LindbladOp`) to retrieve. max_polynomial_vars : int, optional maximum number of variables the created polynomials can have. return_coeff_polys : bool Whether a parallel list of locally-indexed (using variable indices corresponding to *this* object's parameters rather than its parent's) polynomial coefficients should be returned as well. Returns ------- terms : list A list of :class:`RankOneTerm` objects. coefficients : list Only present when `return_coeff_polys == True`. A list of *compact* polynomial objects, meaning that each element is a `(vtape,ctape)` 2-tuple formed by concatenating together the output of :method:`Polynomial.compact`. """ def _compose_poly_indices(terms): for term in terms: term.map_indices_inplace(lambda x: tuple( _modelmember._compose_gpindices(self.gpindices, _np.array(x, _np.int64)))) return terms IDENT = None # sentinel for the do-nothing identity op mpv = max_polynomial_vars if order == 0: polydict = {(): 1.0} for pd in self._get_rate_poly_dicts(): polydict.update({ k: -v for k, v in pd.items() }) # subtracts the "rate" `pd` from `polydict` loc_terms = [ _term.RankOnePolynomialOpTerm.create_from( _Polynomial(polydict, mpv), IDENT, IDENT, self._evotype, self.state_space) ] elif order == 1: loc_terms = [ _term.RankOnePolynomialOpTerm.create_from( _Polynomial(pd, mpv), bel, bel, self._evotype, self.state_space) for i, (pd, bel) in enumerate( zip(self.rate_poly_dicts, self.basis.elements[1:])) ] else: loc_terms = [] # only first order "taylor terms" poly_coeffs = [t.coeff for t in loc_terms] tapes = [poly.compact(complex_coeff_tape=True) for poly in poly_coeffs] if len(tapes) > 0: vtape = _np.concatenate([t[0] for t in tapes]) ctape = _np.concatenate([t[1] for t in tapes]) else: vtape = _np.empty(0, _np.int64) ctape = _np.empty(0, complex) coeffs_as_compact_polys = (vtape, ctape) local_term_poly_coeffs = coeffs_as_compact_polys global_param_terms = _compose_poly_indices(loc_terms) if return_coeff_polys: return global_param_terms, local_term_poly_coeffs else: return global_param_terms