def plot_potential(self, phi_grid: discretization.Grid1d = None, contour_vals: ndarray = None, **kwargs) -> Tuple[Figure, Axes]: """ Draw contour plot of the potential energy. Parameters ---------- phi_grid: used for setting a custom grid for phi; if None use self._default_grid contour_vals: specific contours to draw **kwargs: plot options """ phi_grid = phi_grid or self._default_grid x_vals = y_vals = phi_grid.make_linspace() if "figsize" not in kwargs: kwargs["figsize"] = (5, 5) return plot.contours(x_vals, y_vals, self.potential, contour_vals=contour_vals, **kwargs)
def __init__(self, EJ1, EJ2, EJ3, ECJ1, ECJ2, ECJ3, ECg1, ECg2, ng1, ng2, flux, ncut, truncated_dim=None): self.EJ1 = EJ1 self.EJ2 = EJ2 self.EJ3 = EJ3 self.ECJ1 = ECJ1 self.ECJ2 = ECJ2 self.ECJ3 = ECJ3 self.ECg1 = ECg1 self.ECg2 = ECg2 self.ng1 = ng1 self.ng2 = ng2 self.flux = flux self.ncut = ncut self.truncated_dim = truncated_dim self._sys_type = '3-jct. flux qubit' self._evec_dtype = np.complex_ self._default_grid = Grid1d(-np.pi / 2, 3 * np.pi / 2, 100) # for plotting in phi_j basis
def plot_potential(self, theta_grid: Grid1d = None, contour_vals: Union[List[float], ndarray] = None, **kwargs ) -> Tuple[Figure, Axes]: """Draw contour plot of the potential energy. Parameters ---------- theta_grid: used for setting a custom grid for theta; if None use self._default_grid contour_vals: **kwargs: plotting parameters """ theta_grid = theta_grid or self._default_grid x_vals = self.grid.make_linspace() y_vals = theta_grid.make_linspace() return plot.contours(x_vals, y_vals, self.potential, contour_vals=contour_vals, xlabel=r'$\phi$', ylabel=r'$\theta$', **kwargs)
def __init__(self, EJ, EC, EL, flux, cutoff, truncated_dim=None): self.EJ = EJ self.EC = EC self.EL = EL self.flux = flux self.cutoff = cutoff self.truncated_dim = truncated_dim self._sys_type = 'fluxonium' self._evec_dtype = np.float_ self._default_grid = Grid1d(-4.5 * np.pi, 4.5 * np.pi, 151)
def __init__(self, EJ, EC, ng, ncut, truncated_dim=None): self.EJ = EJ self.EC = EC self.ng = ng self.ncut = ncut self.truncated_dim = truncated_dim self._sys_type = 'transmon' self._evec_dtype = np.float_ self._default_grid = Grid1d(-np.pi, np.pi, 151) self._default_n_range = (-5, 6)
def wavefunction( self, esys: Tuple[ndarray, ndarray] = None, which: int = 0, phi_grid: discretization.Grid1d = None, ) -> storage.WaveFunctionOnGrid: """ Return a flux qubit wave function in phi1, phi2 basis Parameters ---------- esys: eigenvalues, eigenvectors which: index of desired wave function (default value = 0) phi_grid: used for setting a custom grid for phi; if None use self._default_grid """ evals_count = max(which + 1, 3) if esys is None: _, evecs = self.eigensys(evals_count) else: _, evecs = esys phi_grid = phi_grid or self._default_grid dim = 2 * self.ncut + 1 state_amplitudes = np.reshape(evecs[:, which], (dim, dim)) n_vec = np.arange(-self.ncut, self.ncut + 1) phi_vec = phi_grid.make_linspace() a_1_phi = np.exp(1j * np.outer(phi_vec, n_vec)) / (2 * np.pi) ** 0.5 a_2_phi = a_1_phi.T wavefunc_amplitudes = np.matmul(a_1_phi, state_amplitudes) wavefunc_amplitudes = np.matmul(wavefunc_amplitudes, a_2_phi) wavefunc_amplitudes = spec_utils.standardize_phases(wavefunc_amplitudes) grid2d = discretization.GridSpec( np.asarray( [ [phi_grid.min_val, phi_grid.max_val, phi_grid.pt_count], [phi_grid.min_val, phi_grid.max_val, phi_grid.pt_count], ] ) ) return storage.WaveFunctionOnGrid(grid2d, wavefunc_amplitudes)
def create_from_dict(cls, meta_dict): """Set object parameters by given metadata dictionary Parameters ---------- meta_dict: dict """ filtered_dict = {} grid_dict = {} for param_name, param_value in meta_dict.items(): if isinstance(param_value, (int, float, np.number)): if param_name in ['min_val', 'max_val', 'pt_count']: grid_dict[param_name] = param_value else: filtered_dict[param_name] = param_value grid = Grid1d(**grid_dict) filtered_dict['grid'] = grid return cls(**filtered_dict)
def create_from_dict(cls, meta_dict): """Set object parameters by given metadata dictionary Parameters ---------- meta_dict: dict """ filtered_dict = {} grid_dict = {} for param_name, param_value in meta_dict.items(): if key_in_grid1d(param_name): grid_dict[param_name] = param_value elif is_numerical(param_value): filtered_dict[param_name] = param_value grid = Grid1d(**grid_dict) filtered_dict['grid'] = grid return cls(**filtered_dict)
def wavefunction( self, esys: Tuple[ndarray, ndarray] = None, which: int = 0, theta_grid: Grid1d = None, ) -> WaveFunctionOnGrid: """Returns a zero-pi wave function in `phi`, `theta` basis Parameters ---------- esys: eigenvalues, eigenvectors which: index of desired wave function (default value = 0) theta_grid: used for setting a custom grid for theta; if None use self._default_grid """ evals_count = max(which + 1, 3) if esys is None: _, evecs = self.eigensys(evals_count) else: _, evecs = esys theta_grid = theta_grid or self._default_grid dim_theta = 2 * self.ncut + 1 state_amplitudes = evecs[:, which].reshape(self.grid.pt_count, dim_theta) # Calculate psi_{phi, theta} = sum_n state_amplitudes_{phi, n} A_{n, theta} # where a_{n, theta} = 1/sqrt(2 pi) e^{i n theta} n_vec = np.arange(-self.ncut, self.ncut + 1) theta_vec = theta_grid.make_linspace() a_n_theta = np.exp(1j * np.outer(n_vec, theta_vec)) / (2 * np.pi) ** 0.5 wavefunc_amplitudes = np.matmul(state_amplitudes, a_n_theta).T wavefunc_amplitudes = spec_utils.standardize_phases(wavefunc_amplitudes) grid2d = discretization.GridSpec( np.asarray( [ [self.grid.min_val, self.grid.max_val, self.grid.pt_count], [theta_grid.min_val, theta_grid.max_val, theta_grid.pt_count], ] ) ) return storage.WaveFunctionOnGrid(grid2d, wavefunc_amplitudes)
def __init__(self, EJ, EL, ECJ, EC, ng, flux, grid, ncut, dEJ=0, dCJ=0, ECS=None, truncated_dim=None): self.EJ = EJ self.EL = EL self.ECJ = ECJ if EC is None and ECS is None: raise ValueError("Argument missing: must either provide EC or ECS") if EC and ECS: raise ValueError( "Argument error: can only provide either EC or ECS") if EC: self.EC = EC else: self.EC = 1 / (1 / ECS - 1 / self.ECJ) self.dEJ = dEJ self.dCJ = dCJ self.ng = ng self.flux = flux self.grid = grid self.ncut = ncut self.truncated_dim = truncated_dim self._sys_type = '0-pi' self._evec_dtype = np.complex_ self._default_grid = Grid1d( -np.pi / 2, 3 * np.pi / 2, 100) # for theta, needed for plotting wavefunction CENTRAL_DISPATCH.register('GRID_UPDATE', self)
def wavefunction( self, esys: Tuple[ndarray, ndarray] = None, which: int = 0, phi_grid: Grid1d = None, ) -> WaveFunction: """Return the transmon wave function in phase basis. The specific index of the wavefunction is `which`. `esys` can be provided, but if set to `None` then it is calculated on the fly. Parameters ---------- esys: if None, the eigensystem is calculated on the fly; otherwise, the provided eigenvalue, eigenvector arrays as obtained from `.eigensystem()` are used which: eigenfunction index (default value = 0) phi_grid: used for setting a custom grid for phi; if None use self._default_grid """ if esys is None: evals_count = max(which + 1, 3) evals, evecs = self.eigensys(evals_count) else: evals, evecs = esys n_wavefunc = self.numberbasis_wavefunction(esys, which=which) phi_grid = phi_grid or self._default_grid phi_basis_labels = phi_grid.make_linspace() phi_wavefunc_amplitudes = np.empty(phi_grid.pt_count, dtype=np.complex_) for k in range(phi_grid.pt_count): phi_wavefunc_amplitudes[k] = ( 1j**which / math.sqrt(2 * np.pi)) * np.sum( n_wavefunc.amplitudes * np.exp(1j * phi_basis_labels[k] * n_wavefunc.basis_labels)) return storage.WaveFunction( basis_labels=phi_basis_labels, amplitudes=phi_wavefunc_amplitudes, energy=evals[which], )
def plot_wavefunction( self, which: Union[int, Iterable[int]] = 0, mode: str = "real", esys: Tuple[ndarray, ndarray] = None, phi_grid: Grid1d = None, scaling: float = None, **kwargs, ) -> Tuple[Figure, Axes]: """Plot 1d phase-basis wave function(s). Must be overwritten by higher-dimensional qubits like FluxQubits and ZeroPi. Parameters ---------- which: single index or tuple/list of integers indexing the wave function(s) to be plotted. If which is -1, all wavefunctions up to the truncation limit are plotted. mode: choices as specified in `constants.MODE_FUNC_DICT` (default value = 'abs_sqr') esys: eigenvalues, eigenvectors phi_grid: used for setting a custom grid for phi; if None use self._default_grid scaling: custom scaling of wave function amplitude/modulus **kwargs: standard plotting option (see separate documentation) """ wavefunc_indices = process_which(which, self.truncated_dim) if esys is None: evals_count = max(wavefunc_indices) + 1 evals = self.eigenvals(evals_count=evals_count) else: evals, _ = esys energies = evals[list(wavefunc_indices)] phi_grid = phi_grid or self._default_grid potential_vals = self.potential(phi_grid.make_linspace()) amplitude_modifier = constants.MODE_FUNC_DICT[mode] wavefunctions = [] for wavefunc_index in wavefunc_indices: phi_wavefunc = self.wavefunction(esys, which=wavefunc_index, phi_grid=phi_grid) phi_wavefunc.amplitudes = standardize_sign(phi_wavefunc.amplitudes) phi_wavefunc.amplitudes = amplitude_modifier( phi_wavefunc.amplitudes) wavefunctions.append(phi_wavefunc) fig_ax = kwargs.get("fig_ax") or plt.subplots() kwargs["fig_ax"] = fig_ax kwargs = { **self.wavefunction1d_defaults(mode, evals, wavefunc_count=len(wavefunc_indices)), **kwargs, } # in merging the dictionaries in the previous line: if any duplicates, # later ones survive plot.wavefunction1d( wavefunctions, potential_vals=potential_vals, offset=energies, scaling=scaling, **kwargs, ) return fig_ax