Esempio n. 1
0
    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)
Esempio n. 2
0
 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
Esempio n. 3
0
    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)
Esempio n. 4
0
 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)
Esempio n. 5
0
 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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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)
Esempio n. 11
0
    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],
        )
Esempio n. 12
0
    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