def eigensys(self, evals_count=6, filename=None): """Calculates eigenvalues and corresponding eigenvectors using `scipy.linalg.eigh`. Returns two numpy arrays containing the eigenvalues and eigenvectors, respectively. Parameters ---------- evals_count: int, optional number of desired eigenvalues/eigenstates (default value = 6) filename: str, optional path and filename without suffix, if file output desired (default value = None) Returns ------- ndarray, ndarray eigenvalues, eigenvectors """ evals, evecs = self._esys_calc(evals_count) if filename: specdata = SpectrumData('const_parameters', param_vals=np.empty(0), energy_table=evals, system_params=self._get_metadata_dict(), state_table=evecs) specdata.filewrite(filename) return evals, evecs
def eigenvals( self, evals_count: int = 6, filename: str = None, return_spectrumdata: bool = False, ) -> ndarray: """Calculates eigenvalues using `scipy.linalg.eigh`, returns numpy array of eigenvalues. Parameters ---------- evals_count: number of desired eigenvalues/eigenstates (default value = 6) filename: path and filename without suffix, if file output desired (default value = None) return_spectrumdata: if set to true, the returned data is provided as a SpectrumData object (default value = False) Returns ------- eigenvalues as ndarray or in form of a SpectrumData object """ evals = self._evals_calc(evals_count) if filename or return_spectrumdata: specdata = SpectrumData(energy_table=evals, system_params=self.get_initdata()) if filename: specdata.filewrite(filename) return specdata if return_spectrumdata else evals
def eigensys( self, evals_count: int = 6, filename: str = None, return_spectrumdata: bool = False, ) -> Tuple[ndarray, ndarray]: """Calculates eigenvalues and corresponding eigenvectors using `scipy.linalg.eigh`. Returns two numpy arrays containing the eigenvalues and eigenvectors, respectively. Parameters ---------- evals_count: number of desired eigenvalues/eigenstates (default value = 6) filename: path and filename without suffix, if file output desired (default value = None) return_spectrumdata: if set to true, the returned data is provided as a SpectrumData object (default value = False) Returns ------- eigenvalues, eigenvectors as numpy arrays or in form of a SpectrumData object """ evals, evecs = self._esys_calc(evals_count) if filename or return_spectrumdata: specdata = SpectrumData(energy_table=evals, system_params=self.get_initdata(), state_table=evecs) if filename: specdata.filewrite(filename) return specdata if return_spectrumdata else (evals, evecs) # type: ignore
def generate_diffspec_sweep(sweep, initial_state_ind=0): """Takes spectral data of energy eigenvalues and subtracts the energy of a select state, given by its state index. Parameters ---------- sweep: ParameterSweep initial_state_ind: int or (i1, i2, ...) index of the initial state whose energy is supposed to be subtracted from the spectral data Returns ------- SpectrumData """ lookup = sweep.lookup param_count = sweep.param_count evals_count = sweep.evals_count diff_eigenenergy_table = np.empty(shape=(param_count, evals_count)) for param_index in tqdm(range(param_count), desc="difference spectrum", **TQDM_KWARGS): eigenenergies = sweep.dressed_specdata.energy_table[param_index] if isinstance(initial_state_ind, int): eigenenergy_index = initial_state_ind else: eigenenergy_index = lookup.dressed_index(initial_state_ind, param_index) diff_eigenenergies = eigenenergies - eigenenergies[eigenenergy_index] diff_eigenenergy_table[param_index] = diff_eigenenergies return SpectrumData(diff_eigenenergy_table, sweep.system_params, sweep.param_name, sweep.param_vals)
def test_matrixelement_table(self, io_type): testname = self.file_str + '_5.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) matelem_reference = specdata.matrixelem_table return self.matrixelement_table(io_type, self.op1_str, matelem_reference)
def bare_specdata_list(self) -> List[SpectrumData]: """ Wrap bare eigensystem data into a SpectrumData object. To be used with pre-slicing, e.g. `<ParameterSweep>[0, :].bare_specdata_list` Returns ------- List of `SpectrumData` objects with bare eigensystem data, one per subsystem """ multi_index = self._current_param_indices sweep_param_indices = self.get_sweep_indices(multi_index) if len(sweep_param_indices) != 1: raise ValueError( "All but one parameter must be fixed for `bare_specdata_list`." ) sweep_param_name = self._parameters.name_by_index[ sweep_param_indices[0]] specdata_list: List[SpectrumData] = [] for subsys_index, subsystem in enumerate(self._hilbertspace): evals_swp = self["bare_evals"][subsys_index][multi_index] evecs_swp = self["bare_evecs"][subsys_index][multi_index] specdata_list.append( SpectrumData( energy_table=evals_swp.toarray(), state_table=evecs_swp.toarray(), system_params=self._hilbertspace.get_initdata(), param_name=sweep_param_name, param_vals=self._parameters[sweep_param_name], )) self._current_param_indices = None return specdata_list
def _recast_bare_eigendata(self, static_eigendata, bare_eigendata): """ Parameters ---------- static_eigendata: list of eigensystem tuples bare_eigendata: list of eigensystem tuples Returns ------- list of SpectrumData """ specdata_list = [] for index, subsys in enumerate(self._hilbertspace): if subsys in self.subsys_update_list: eigendata = bare_eigendata else: eigendata = static_eigendata evals_count = subsys.truncated_dim dim = subsys.hilbertdim() esys_dtype = subsys._evec_dtype energy_table = np.empty(shape=(self.param_count, evals_count), dtype=np.float_) state_table = np.empty(shape=(self.param_count, dim, evals_count), dtype=esys_dtype) for j in range(self.param_count): energy_table[j] = eigendata[j][index][0] state_table[j] = eigendata[j][index][1] specdata_list.append(SpectrumData(energy_table, subsys.__dict__, self.param_name, self.param_vals, state_table)) return specdata_list
def dressed_specdata(self) -> "SpectrumData": """ Wrap dressed eigensystem data into a SpectrumData object. To be used with pre-slicing, e.g. `<ParameterSweep>[0, :].dressed_specdata` Returns ------- `SpectrumData` object with bare eigensystem data """ multi_index = self._current_param_indices sweep_param_indices = self.get_sweep_indices(multi_index) if len(sweep_param_indices) != 1: raise ValueError( "All but one parameter must be fixed for `dressed_specdata`.") sweep_param_name = self._parameters.name_by_index[ sweep_param_indices[0]] specdata = SpectrumData( energy_table=self["evals"][multi_index].toarray(), state_table=self["evecs"][multi_index].toarray(), system_params=self._hilbertspace.get_initdata(), param_name=sweep_param_name, param_vals=self._parameters[sweep_param_name], ) self._current_param_indices = None return specdata
def test_hamiltonian_is_hermitean(self, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) hamiltonian = self.qbt.hamiltonian() assert np.isclose(np.max(np.abs(hamiltonian - hamiltonian.conj().T)), 0.0)
def test_plot_potential(self, io_type): testname = self.file_str + '_1.hdf5' specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) if 'plot_potential' not in dir(self.qbt): pytest.skip('This is expected, no reason for concern.') self.qbt.plot_potential()
def test_plot_evals_vs_paramvals(self, num_cpus, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type.create_from_dict( specdata._get_metadata_dict()) return self.plot_evals_vs_paramvals(num_cpus, self.param_name, self.param_list)
def test_plot_wavefunction(self, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type.create_from_dict( specdata._get_metadata_dict()) self.qbt.plot_wavefunction(esys=None, which=5, mode='real') self.qbt.plot_wavefunction(esys=None, which=9, mode='abs_sqr')
def test_eigenvecs(self, io_type): testname = self.file_str + '_2.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type.create_from_dict( specdata._get_metadata_dict()) evecs_reference = specdata.state_table return self.eigenvecs(io_type, evecs_reference)
def get_difference_spectrum(sweep, initial_state_ind=0, lookup=None): """Takes spectral data of energy eigenvalues and subtracts the energy of a select state, given by its state index. Parameters ---------- sweep: ParameterSweep initial_state_ind: int or (i1, i2, ...) index of the initial state whose energy is supposed to be subtracted from the spectral data lookup: SpectrumLookup, optional Returns ------- SpectrumData object """ lookup = lookup or SpectrumLookup(sweep) param_count = sweep.param_count evals_count = sweep.evals_count diff_eigenenergy_table = np.empty(shape=(param_count, evals_count)) for param_index in tqdm(range(param_count), desc="difference spectrum", **TQDM_KWARGS): eigenenergies = sweep.dressed_specdata.energy_table[param_index] if isinstance(initial_state_ind, int): eigenenergy_index = initial_state_ind else: eigenenergy_index = lookup.dressed_index(initial_state_ind, param_index) diff_eigenenergies = eigenenergies - eigenenergies[eigenenergy_index] diff_eigenenergy_table[param_index] = diff_eigenenergies return SpectrumData(sweep.param_name, sweep.param_vals, diff_eigenenergy_table, sweep.hilbertspace.__dict__)
def generate_lookup(self): bare_specdata_list = [] for index, subsys in enumerate(self): evals, evecs = subsys.eigensys(evals_count=subsys.truncated_dim) bare_specdata_list.append( SpectrumData(energy_table=[evals], state_table=[evecs], system_params=subsys.__dict__)) evals, evecs = self.eigensys(evals_count=self.dimension) dressed_specdata = SpectrumData( energy_table=[evals], state_table=[evecs], system_params=self._get_metadata_dict()) self._lookup = SpectrumLookup(self, bare_specdata_list=bare_specdata_list, dressed_specdata=dressed_specdata)
def test_matrixelement_table(self, io_type): testname = self.file_str + '_5.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type.create_from_dict( specdata._get_metadata_dict()) matelem_reference = specdata.matrixelem_table return self.matrixelement_table(io_type, self.op1_str, matelem_reference)
def test_hamiltonian_is_hermitean(self, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) if not hasattr(self.qbt, 'hamiltonian'): pytest.skip('This is expected, no reason for concern.') hamiltonian = self.qbt.hamiltonian() assert np.isclose(np.max(np.abs(hamiltonian - hamiltonian.conj().T)), 0.0)
def test_plot_matelem_vs_paramvals(self, num_cpus, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) self.plot_matelem_vs_paramvals(num_cpus, self.op1_str, self.param_name, self.param_list, select_elems=[(0, 0), (1, 4), (1, 0)])
def test_get_spectrum_vs_paramvals(self, num_cpus, io_type): testname = self.file_str + '_4.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) self.param_list = specdata.param_vals evecs_reference = specdata.state_table evals_reference = specdata.energy_table return self.get_spectrum_vs_paramvals(num_cpus, io_type, self.param_name, self.param_list, evals_reference, evecs_reference)
def eigenvals(self, evals_count=6, filename=None): """Calculates eigenvalues using `scipy.linalg.eigh`, returns numpy array of eigenvalues. Parameters ---------- evals_count: int number of desired eigenvalues/eigenstates (default value = 6) filename: str, optional path and filename without suffix, if file output desired (default value = None) Returns ------- ndarray """ evals = self._evals_calc(evals_count) if filename: specdata = SpectrumData(energy_table=evals, system_params=self._get_metadata_dict()) specdata.filewrite(filename) return evals
def get_matelements_vs_paramvals(self, operator, param_name, param_vals, evals_count=6): """Calculates matrix elements for a varying system parameter, given an array of parameter values. Returns a `SpectrumData` object containing matrix element data, eigenvalue data, and eigenstate data.. Parameters ---------- operator: str name of class method in string form, returning operator matrix param_name: str name of parameter to be varied param_vals: ndarray parameter values to be plugged in evals_count: int, optional number of desired eigenvalues (sorted from smallest to largest) (default value = 6) Returns ------- SpectrumData object """ previous_paramval = getattr(self, param_name) paramvals_count = len(param_vals) eigenvalue_table = np.zeros((paramvals_count, evals_count), dtype=np.float_) eigenstate_table = np.empty(shape=(paramvals_count, self.hilbertdim(), evals_count), dtype=np.complex_) matelem_table = np.empty(shape=(paramvals_count, evals_count, evals_count), dtype=np.complex_) for index, paramval in tqdm(enumerate(param_vals), total=len(param_vals), **TQDM_KWARGS): setattr(self, param_name, paramval) evals, evecs = self.eigensys(evals_count) eigenstate_table[index] = evecs eigenvalue_table[index] = evals matelem_table[index] = self.matrixelement_table( operator, evals_count=evals_count) setattr(self, param_name, previous_paramval) spectrumdata = SpectrumData(param_name, param_vals, eigenvalue_table, self._get_metadata_dict(), state_table=eigenstate_table, matrixelem_table=matelem_table) return spectrumdata
def matrixelement_table(self, operator, evecs=None, evals_count=6, filename=None): """Returns table of matrix elements for `operator` with respect to the eigenstates of the qubit. The operator is given as a string matching a class method returning an operator matrix. E.g., for an instance `trm` of Transmon, the matrix element table for the charge operator is given by `trm.op_matrixelement_table('n_operator')`. When `esys` is set to `None`, the eigensystem is calculated on-the-fly. Parameters ---------- operator: str name of class method in string form, returning operator matrix in qubit-internal basis. evecs: ndarray, optional if not provided, then the necesssary eigenstates are calculated on the fly evals_count: int, optional number of desired matrix elements, starting with ground state (default value = 6) filename: str, optional output file name Returns ------- ndarray """ if evecs is None: _, evecs = self.eigensys(evals_count=evals_count) operator_matrix = getattr(self, operator)() table = get_matrixelement_table(operator_matrix, evecs) if filename: specdata = SpectrumData(energy_table=np.empty(0), system_params=self._get_metadata_dict(), param_name='const_parameters', param_vals=np.empty(0), matrixelem_table=table) specdata.filewrite(filename) return table
def get_spectrum_vs_paramvals(self, hamiltonian_func, param_vals, evals_count=10, get_eigenstates=False, param_name="external_parameter"): """Return eigenvalues (and optionally eigenstates) of the full Hamiltonian as a function of a parameter. Parameter values are specified as a list or array in `param_vals`. The Hamiltonian `hamiltonian_func` must be a function of that particular parameter, and is expected to internally set subsystem parameters. If a `filename` string is provided, then eigenvalue data is written to that file. Parameters ---------- hamiltonian_func: function of one parameter function returning the Hamiltonian in `qutip.Qobj` format param_vals: ndarray of floats array of parameter values evals_count: int, optional number of desired energy levels (default value = 10) get_eigenstates: bool, optional set to true if eigenstates should be returned as well (default value = False) param_name: str, optional name for the parameter that is varied in `param_vals` (default value = "external_parameter") Returns ------- SpectrumData object """ paramvals_count = len(param_vals) eigenenergy_table = np.empty((paramvals_count, evals_count)) if get_eigenstates: eigenstates_qobj_table = [0] * paramvals_count else: eigenstates_qobj_table = None for param_index, paramval in tqdm(enumerate(param_vals), total=len(param_vals), **TQDM_KWARGS): paramval = param_vals[param_index] hamiltonian = hamiltonian_func(paramval) if get_eigenstates: eigenenergies, eigenstates_qobj = hamiltonian.eigenstates(eigvals=evals_count) eigenenergy_table[param_index] = eigenenergies eigenstates_qobj_table[param_index] = eigenstates_qobj else: eigenenergies = hamiltonian.eigenenergies(eigvals=evals_count) eigenenergy_table[param_index] = eigenenergies spectrumdata = SpectrumData(param_name, param_vals, eigenenergy_table, self.__dict__, state_table=eigenstates_qobj_table) return spectrumdata
def get_n_photon_qubit_spectrum(sweep, photonnumber, initial_state_labels, lookup=None): """ Extracts energies for transitions among qubit states only, while all oscillator subsystems maintain their excitation level. Parameters ---------- sweep: ParameterSweep photonnumber: int number of photons used in transition initial_state_labels: tuple(int1, int2, ...) bare-state labels of the initial state whose energy is supposed to be subtracted from the spectral data lookup: SpectrumLookup, optional Returns ------- SpectrumData object """ lookup = lookup or SpectrumLookup(sweep) target_states_list = generate_target_states_list(sweep, initial_state_labels) difference_energies_table = [] for param_index in tqdm(range(sweep.param_count), desc="n-photon spectrum", **TQDM_KWARGS): difference_energies = [] initial_energy = lookup.energy_bare_index(initial_state_labels, param_index) for target_labels in target_states_list: target_energy = lookup.energy_bare_index(target_labels, param_index) if target_energy is None or initial_energy is None: difference_energies.append(np.NaN) else: difference_energies.append( (target_energy - initial_energy) / photonnumber) difference_energies_table.append(difference_energies) return target_states_list, SpectrumData( sweep.param_name, sweep.param_vals, np.asarray(difference_energies_table), sweep.hilbertspace.__dict__)
def generate_qubit_transitions_sweep(sweep, photonnumber, initial_state_labels): """ Extracts energies for transitions among qubit states only, while all oscillator subsystems maintain their excitation level. Parameters ---------- sweep: ParameterSweep photonnumber: int number of photons used in transition initial_state_labels: tuple(int1, int2, ...) bare-state labels of the initial state whose energy is supposed to be subtracted from the spectral data Returns ------- list, SpectrumData list of transition target states, spectrum data """ lookup = sweep.lookup target_states_list = generate_target_states_list(sweep, initial_state_labels) difference_energies_table = [] for param_index in range(sweep.param_count): difference_energies = [] initial_energy = lookup.energy_bare_index(initial_state_labels, param_index) for target_labels in target_states_list: target_energy = lookup.energy_bare_index(target_labels, param_index) if target_energy is None or initial_energy is None: difference_energies.append(np.NaN) else: difference_energies.append( (target_energy - initial_energy) / photonnumber) difference_energies_table.append(difference_energies) data = np.asarray(difference_energies_table) specdata = SpectrumData(data, sweep.system_params, sweep.param_name, sweep.param_vals) return target_states_list, specdata
def _recast_dressed_eigendata(self, dressed_eigendata): """ Parameters ---------- dressed_eigendata: list of tuple(evals, qutip evecs) Returns ------- SpectrumData """ evals_count = self.evals_count energy_table = np.empty(shape=(self.param_count, evals_count), dtype=np.float_) state_table = [] # for dressed states, entries are Qobj for j in range(self.param_count): energy_table[j] = dressed_eigendata[j][0] state_table.append(dressed_eigendata[j][1]) specdata = SpectrumData(energy_table, system_params=self._hilbertspace._get_metadata_dict(), param_name=self.param_name, param_vals=self.param_vals, state_table=state_table) return specdata
def get_spectrum_vs_paramvals( self, param_name: str, param_vals: ndarray, evals_count: int = 6, subtract_ground: bool = False, get_eigenstates: bool = False, filename: str = None, num_cpus: int = settings.NUM_CPUS, ) -> SpectrumData: """Calculates eigenvalues/eigenstates for a varying system parameter, given an array of parameter values. Returns a `SpectrumData` object with `energy_data[n]` containing eigenvalues calculated for parameter value `param_vals[n]`. Parameters ---------- param_name: name of parameter to be varied param_vals: parameter values to be plugged in evals_count: number of desired eigenvalues (sorted from smallest to largest) (default value = 6) subtract_ground: if True, eigenvalues are returned relative to the ground state eigenvalue (default value = False) get_eigenstates: return eigenstates along with eigenvalues (default value = False) filename: file name if direct output to disk is wanted num_cpus: number of cores to be used for computation (default value: settings.NUM_CPUS) """ previous_paramval = getattr(self, param_name) tqdm_disable = num_cpus > 1 or settings.PROGRESSBAR_DISABLED target_map = get_map_method(num_cpus) if not get_eigenstates: func = functools.partial(self._evals_for_paramval, param_name=param_name, evals_count=evals_count) with InfoBar( "Parallel computation of eigensystems [num_cpus={}]". format(num_cpus), num_cpus, ): eigenvalue_table = list( target_map( func, tqdm( param_vals, desc="Spectral data", leave=False, disable=tqdm_disable, ), )) eigenvalue_table = np.asarray(eigenvalue_table) eigenstate_table = None else: func = functools.partial(self._esys_for_paramval, param_name=param_name, evals_count=evals_count) with InfoBar( "Parallel computation of eigenvalues [num_cpus={}]".format( num_cpus), num_cpus, ): # Note that it is useful here that the outermost eigenstate object is # a list, as for certain applications the necessary hilbert space # dimension can vary with paramvals eigensystem_mapdata = list( target_map( func, tqdm( param_vals, desc="Spectral data", leave=False, disable=tqdm_disable, ), )) eigenvalue_table, eigenstate_table = recast_esys_mapdata( eigensystem_mapdata) if subtract_ground: for param_index, _ in enumerate(param_vals): eigenvalue_table[param_index] -= eigenvalue_table[param_index][ 0] setattr(self, param_name, previous_paramval) specdata = SpectrumData( eigenvalue_table, self.get_initdata(), param_name, param_vals, state_table=eigenstate_table, ) if filename: specdata.filewrite(filename) return SpectrumData( eigenvalue_table, self.get_initdata(), param_name, param_vals, state_table=eigenstate_table, )
def test_print_matrixelements(self, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) self.print_matrixelements(self.op2_str)
def test_plot_evals_vs_paramvals(self, num_cpus, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) return self.plot_evals_vs_paramvals(num_cpus, self.param_name, self.param_list)
def test_plot_wavefunction(self, io_type): testname = self.file_str + '_1.' + io_type specdata = SpectrumData.create_from_file(DATADIR + testname) self.qbt = self.qbt_type(**specdata.system_params) self.qbt.plot_wavefunction(esys=None, which=5, mode='real') self.qbt.plot_wavefunction(esys=None, which=9, mode='abs_sqr')