def _dressed_spectrum_sweep( self, ) -> Tuple[NamedSlotsNdarray, NamedSlotsNdarray]: """ Returns ------- NamedSlotsNdarray[<paramname1>, <paramname2>, ...] of eigenvalues, likewise for eigenvectors """ multi_cpu = self._num_cpus > 1 target_map = cpu_switch.get_map_method(self._num_cpus) total_count = np.prod(self._parameters.counts) with utils.InfoBar( "Parallel compute dressed eigensys [num_cpus={}]".format( self._num_cpus), self._num_cpus, ) as p: spectrum_data = list( tqdm( target_map( functools.partial( self._update_and_compute_dressed_esys, self._hilbertspace, self._evals_count, self._update_hilbertspace, ), itertools.product(*self._parameters.ranges), ), total=total_count, desc="Dressed spectrum", leave=False, disable=multi_cpu, )) spectrum_data = np.asarray(spectrum_data, dtype=object) spectrum_data = spectrum_data.reshape((*self._parameters.counts, 2)) slotparamvals_by_name = OrderedDict( self._parameters.ordered_dict.copy()) evals = np.asarray(spectrum_data[..., 0].tolist()) evecs = spectrum_data[..., 1] return NamedSlotsNdarray(evals, slotparamvals_by_name), NamedSlotsNdarray( evecs, slotparamvals_by_name)
def generator(sweep: "ParameterSweep", func: callable, **kwargs) -> np.ndarray: """Method for computing custom data as a function of the external parameter, calculated via the function `func`. Parameters ---------- sweep: ParameterSweep object containing HilbertSpace and spectral information func: signature: `func(parametersweep, [paramindex_tuple, paramvals_tuple, **kwargs])`, specifies how to calculate the data for a single choice of parameter(s) **kwargs: keyword arguments to be included in func Returns ------- array of custom data """ reduced_parameters = sweep._parameters.create_sliced( sweep._current_param_indices, remove_fixed=False) total_count = np.prod(reduced_parameters.counts) def func_effective(paramindex_tuple: Tuple[int], params, **kw) -> Any: paramvals_tuple = params[paramindex_tuple] return func( sweep, paramindex_tuple=paramindex_tuple, paramvals_tuple=paramvals_tuple, **kw, ) if hasattr(func, "__name__"): func_name = func.__name__ else: func_name = "" data_array = list( tqdm( map( functools.partial( func_effective, params=reduced_parameters, **kwargs, ), itertools.product(*reduced_parameters.ranges), ), total=total_count, desc="sweeping " + func_name, leave=False, disable=settings.PROGRESSBAR_DISABLED, )) data_array = np.asarray(data_array) return NamedSlotsNdarray( data_array.reshape(reduced_parameters.counts), reduced_parameters.paramvals_by_name, )
def energy_by_bare_index( self: "ParameterSweep", bare_tuple: Tuple[int, ...], subtract_ground: bool = False, param_indices: Optional[NpIndices] = None, ) -> NamedSlotsNdarray: """ Look up dressed energy most closely corresponding to the given bare-state labels Parameters ---------- bare_tuple: bare state indices subtract_ground: whether to subtract the ground state energy param_indices: indices specifying the set of parameters Returns ------- dressed energies, if lookup successful, otherwise nan; """ param_indices = param_indices or self._current_param_indices dressed_index = self.dressed_index(bare_tuple, param_indices) if dressed_index is None: return np.nan if isinstance(dressed_index, int): energy = self["evals"][param_indices + (dressed_index, )] if subtract_ground: energy -= self["evals"][param_indices + (0, )] return energy dressed_index = np.asarray(dressed_index) energies = np.empty_like(dressed_index) it = np.nditer(dressed_index, flags=["multi_index", "refs_ok"]) sliced_energies = self["evals"][param_indices] for location in it: location = location.tolist() if location is None: energies[it.multi_index] = np.nan else: energies[it.multi_index] = sliced_energies[ it.multi_index][location] if subtract_ground: energies[it.multi_index] -= sliced_energies[ it.multi_index][0] return NamedSlotsNdarray(energies, sliced_energies._parameters.paramvals_by_name)
def _bare_spectrum_sweep( self) -> Tuple[NamedSlotsNdarray, NamedSlotsNdarray]: """ The bare energy spectra are computed according to the following scheme. 1. Perform a loop over all subsystems to separately obtain the bare energy eigenvalues and eigenstates for each subsystems. 2. If `update_subsystem_info` is given, remove those sweeps that leave the subsystems fixed. 3. If self._num_cpus > 1, parallelize. Returns ------- NamedSlotsNdarray[<paramname1>, <paramname2>, ..., "subsys"] for evals, likewise for evecs; here, "subsys": 0, 1, ... enumerates subsystems and """ bare_evals = np.empty((self.subsystem_count, ), dtype=object) bare_evecs = np.empty((self.subsystem_count, ), dtype=object) for subsys_index, subsystem in enumerate(self._hilbertspace): bare_esys = self._subsys_bare_spectrum_sweep(subsystem) bare_evals[subsys_index] = NamedSlotsNdarray( np.asarray(bare_esys[..., 0].tolist()), self._parameters.paramvals_by_name, ) bare_evecs[subsys_index] = NamedSlotsNdarray( np.asarray(bare_esys[..., 1].tolist()), self._parameters.paramvals_by_name, ) return ( NamedSlotsNdarray(bare_evals, {"subsys": np.arange(self.subsystem_count)}), NamedSlotsNdarray(bare_evecs, {"subsys": np.arange(self.subsystem_count)}), )
def generate_lookup(self: "ParameterSweep") -> NamedSlotsNdarray: """ For each parameter value of the parameter sweep, generate the map between bare states and dressed states. Returns ------- each list item is a list of dressed indices whose order corresponds to the ordering of bare indices (as stored in .canonical_bare_labels, thus establishing the mapping) """ dressed_indices = np.empty(shape=self._parameters.counts, dtype=object) param_indices = itertools.product(*map(range, self._parameters.counts)) for index in param_indices: dressed_indices[index] = self._generate_single_mapping(index) dressed_indices = np.asarray(dressed_indices[:].tolist()) parameter_dict = self._parameters.ordered_dict.copy() return NamedSlotsNdarray(dressed_indices, parameter_dict)
def test_named_slice(): tst = NamedSlotsNdarray(data, paramvals_by_name) assert np.allclose(tst["p2":2:-1], data[:, 2:-1, :]) assert np.allclose(tst["p2":2, "p1":0], tst["p1":0, "p2":2])
def test_value_access(): tst = NamedSlotsNdarray(data, paramvals_by_name) param_val = float(paramvals1[4]) assert np.allclose(tst["p1":param_val], data[4, :, :])
def test_name_access(): tst = NamedSlotsNdarray(data, paramvals_by_name) assert np.allclose(tst["p2":1], data[:, 1, :])
def test_index_access(): tst = NamedSlotsNdarray(data, paramvals_by_name) assert np.allclose(tst[0], data[0])
def test_initialize(): tst = NamedSlotsNdarray(data, paramvals_by_name)
def _dispersive_coefficients( self, ) -> Tuple[NamedSlotsNdarray, NamedSlotsNdarray, NamedSlotsNdarray]: energy_0 = self[:].energy_by_dressed_index(0).toarray() lamb_data = np.empty(self.subsystem_count, dtype=object) kerr_data = np.empty((self.subsystem_count, self.subsystem_count), dtype=object) for subsys_index1, subsys1 in enumerate(self._hilbertspace): energy_subsys1_all_l1 = self._energies_1(subsys1) bare_energy_subsys1_all_l1 = self["bare_evals"][ subsys_index1].toarray() lamb_subsys1_all_l1 = ( energy_subsys1_all_l1 - energy_0[..., None] - bare_energy_subsys1_all_l1 + bare_energy_subsys1_all_l1[..., 0][..., None]) lamb_data[subsys_index1] = NamedSlotsNdarray( lamb_subsys1_all_l1, self._parameters.paramvals_by_name) for subsys_index2, subsys2 in enumerate(self._hilbertspace): energy_subsys2_all_l2 = self._energies_1(subsys2) energy_subsys1_subsys2_all_l1_l2 = self._energies_2( subsys1, subsys2) kerr_subsys1_subsys2_all_l1_l2 = ( energy_subsys1_subsys2_all_l1_l2 + energy_0[..., None, None] - energy_subsys1_all_l1[..., :, None] - energy_subsys2_all_l2[..., None, :]) if subsys1 is subsys2: kerr_subsys1_subsys2_all_l1_l2 /= 2.0 # self-Kerr needs factor 1/2 kerr_data[subsys_index1, subsys_index2] = NamedSlotsNdarray( kerr_subsys1_subsys2_all_l1_l2, self._parameters.paramvals_by_name) sys_indices = np.arange(self.subsystem_count) lamb_data = NamedSlotsNdarray(lamb_data, {"subsys": sys_indices}) kerr_data = NamedSlotsNdarray(kerr_data, { "subsys1": sys_indices, "subsys2": sys_indices }) chi_data = kerr_data.copy() for subsys_index1, subsys1 in enumerate(self._hilbertspace): for subsys_index2, subsys2 in enumerate(self._hilbertspace): if subsys1 in self.osc_subsys_list: if subsys2 in self.qbt_subsys_list: chi_data[subsys_index1, subsys_index2] = chi_data[subsys_index1, subsys_index2][..., 1, :] kerr_data[subsys_index1, subsys_index2] = np.asarray([]) else: chi_data[subsys_index1, subsys_index2] = np.asarray([]) elif subsys1 in self.qbt_subsys_list: if subsys2 in self.osc_subsys_list: chi_data[subsys_index1, subsys_index2] = chi_data[ subsys_index1, subsys_index2][..., :, 1] kerr_data[subsys_index1, subsys_index2] = np.asarray([]) else: chi_data[subsys_index1, subsys_index2] = np.asarray([]) return lamb_data, chi_data, kerr_data