def __init__(self, N: int, V: float, geometry: BaseGeometry, Omega: np.ndarray, Delta: np.ndarray, t_list: np.ndarray, ghz_state: BaseGHZState, solve_points_per_timestep: int = 1): super().__init__(N, V, geometry) self.Omega = Omega self.Delta = Delta self.t_list = t_list assert len(t_list) - 1 == len(Omega) == len(Delta), \ "Omega and Delta need to be of equal length, and of length one less than t_list" self.psi_0 = q.kron(*states_quimb.get_ground_states(N)) self.ghz_state = ghz_state self.solve_points_per_timestep = solve_points_per_timestep self.evo: Optional[q.Evolution] = None self.solved_states: List[q.qarray] = [] self.solved_t_list = []
def get_fidelity_with(self, target_state: Union[str, q.qarray] = "ghz") -> float: """ :param target_state: One of "ghz", "ghz_antisymmetric", "ground", and "excited". Can also be ghz_component_1 or ghz_component_2 :return: """ assert ( self.evo is not None), "evo attribute cannot be None (call solve method)" final_state = self.solved_states[-1] if target_state == "ghz": return q.fidelity(final_state, self.ghz_state.get_state_tensor(symmetric=True)) elif target_state == "ghz_antisymmetric": return q.fidelity(final_state, self.ghz_state.get_state_tensor(symmetric=False)) elif target_state == "ghz_component_1": return q.fidelity(final_state, self.ghz_state._get_components()[0]) elif target_state == "ghz_component_2": return q.fidelity(final_state, self.ghz_state._get_components()[1]) elif target_state == "ground": return q.fidelity(final_state, q.kron(*states_quimb.get_ground_states(self.N))) elif target_state == "excited": return q.fidelity(final_state, q.kron(*states_quimb.get_excited_states(self.N))) elif isinstance(target_state, q.qarray): return q.fidelity(final_state, target_state) else: raise ValueError( f"target_state has to be one of 'ghz', 'ground', or 'excited', not {target_state}." )
def plot_detuning_energy_levels(s_qs: StaticQubitSystem, crossings: np.ndarray, ax: Axes, highlighted_indices: Sequence[int] = (-1, )): if s_qs.Omega_zero_energies is None: s_qs.get_energies() crossings_range = crossings.max() - crossings.min() xlims = crossings_range * -0.1, crossings.max() * 1.1 s_qs = StaticQubitSystem(s_qs.N, s_qs.V, s_qs.geometry, Omega=0, Delta=np.linspace(xlims[0], xlims[1], 20)) s_qs.get_energies() g = states_quimb.get_ground_states(1)[0] for i, state in enumerate(s_qs.states): is_highlight_state = any(state is s_qs.states[i] for i in highlighted_indices) is_ground_state = all((_state == g).all() for _state in state) color = 'g' if is_ground_state else 'r' if is_highlight_state else 'grey' linewidth = 5 if is_ground_state or is_highlight_state else 1 z_order = 2 if is_ground_state or is_highlight_state else 1 energies = s_qs.Omega_zero_energies[:, i] ax.plot(s_qs.Delta, energies, color=color, alpha=0.6, lw=linewidth, zorder=z_order, label=states_quimb.get_label_from_state(state), picker=3) def on_pick(event): line = event.artist print(f'Clicked on: {line.get_label()}') plt.gcf().canvas.mpl_connect('pick_event', on_pick) ax.grid() scaled_xaxis_ticker = ticker.EngFormatter(unit="Hz") scaled_yaxis_ticker = ticker.EngFormatter(unit="Hz") ax.xaxis.set_major_formatter(scaled_xaxis_ticker) ax.yaxis.set_major_formatter(scaled_yaxis_ticker) ax.locator_params(nbins=4) # plt.title(rf"Energy spectrum with $N = {self.N}$, $V = {self.V:0.2e}$, $\Omega = {self.Omega:0.2e}$") _m, _s = f"{s_qs.V:0.2e}".split('e') V_text = rf"{_m:s} \times 10^{{{int(_s):d}}}" plt.title(rf"Energy spectrum with $N = {s_qs.N}$, $V = {V_text:s}$ Hz") plt.xlabel(r"Detuning $\Delta$") plt.ylabel("Eigenenergy") plt.xlim(xlims) plt.tight_layout()
def __init__(self, N: int, V: float, geometry: BaseGeometry, t_list: np.ndarray, ghz_state: BaseGHZState, Omega_range: Tuple[float, float], Delta_range: Tuple[float, float], verbose: bool = False): self.verbose = verbose self.ti_evolving_qubit_system_kwargs = { 'N': N, 'V': V, 'geometry': geometry, 'ghz_state': ghz_state, 't_list': np.linspace(0, t_list[1], 10) } self.psi_0 = q.kron(*states_quimb.get_ground_states(N)) self.t_list = t_list self.required_steps = len(t_list) - 1 # Actions for all ts except the end. self.recorded_steps = { 'Omega': [], 'Delta': [], } self.step_number = 0 self.latest_evolving_qubit_system: Optional[ TimeIndependentEvolvingQubitSystem] = None self.total_solve_time = 0 self.action_normalisation = Omega_range, Delta_range self.action_space = gym.spaces.Box(low=np.array([0, 0], dtype=np.float32), high=np.array([1, 1], dtype=np.float32)) # Using action_normalisation as PPO policy generates actions of order 1 self.observation_space = gym.spaces.Discrete(self.required_steps) self._maximum_fidelity_achieved = 0.505
def __init__(self, N: int, V: float, geometry: BaseGeometry, Omega: float, Delta: float, t_list: np.ndarray, ghz_state: BaseGHZState, psi_0: q.qarray = None): super().__init__(N, V, geometry) self.Omega = Omega self.Delta = Delta self.t_list = t_list self.psi_0 = q.kron(*states_quimb.get_ground_states( N, sparse=True)) if psi_0 is None else psi_0 self.ghz_state = ghz_state self.evo: Optional[q.Evolution] = None self.solved_states: List[q.qarray] = []
def plot_basis_states_overlaps(self, ax, plot_title: bool = True, plot_others_as_sum: bool = False): states = states_quimb.get_states(self.N) if not plot_others_as_sum \ else [states_quimb.get_excited_states(self.N), states_quimb.get_ground_states(self.N)] fidelities = [] plot_individual_orthogonal_state_labels = len(states) <= 4 plotted_others = False # for i, state in enumerate(tqdm(states)): for i, state in enumerate(states): label = states_quimb.get_label_from_state(state) state_product_basis_index = states_quimb.get_product_basis_states_index( state) state_fidelities = [ np.abs(_instantaneous_state.flatten() [state_product_basis_index])**2 for _instantaneous_state in self.solved_states ] if 'e' not in label or 'g' not in label: fidelities.append(state_fidelities) if ('e' not in label or 'g' not in label): plot_label = r"$P_{" + f"{label.upper()[0]}" + "}$" elif plot_individual_orthogonal_state_labels: plot_label = r"$P_{" + f"{label.upper()}" + "}$" else: plot_label = 'Others' if plot_label == 'Others': if plotted_others: plot_label = None else: plotted_others = True ax.plot( self.solved_t_list, state_fidelities, label=plot_label, color='g' if 'e' not in label else 'r' if 'g' not in label else 'k', linewidth=1 if 'e' not in label or 'g' not in label else 0.5, alpha=0.5) fidelities_sum = np.array(fidelities).sum(axis=0) ax.plot(self.solved_t_list, fidelities_sum, label="$P_{E} + P_{G}$", color='C0', linestyle=":", linewidth=1, alpha=0.7) if plot_others_as_sum: others_sum = 1 - fidelities_sum ax.plot(self.solved_t_list, others_sum, label=r"$\sum{\textrm{Others}}$", color='C1', linestyle=":", linewidth=1, alpha=0.7) ax.set_ylabel("Population") if plot_title: ax.set_title("Basis state populations") ax.set_ylim((-0.1, 1.1)) ax.yaxis.set_ticks([0, 0.5, 1]) # ax.legend() handles, labels = ax.get_legend_handles_labels() # sort both labels and handles by labels labels, handles = zip(*sorted(zip(labels, handles))) ax.legend(handles, labels)
def _get_components(self) -> Tuple[q.qarray, q.qarray]: return q.kron(*get_ground_states(self.N, sparse=True)), q.kron( *get_excited_states(self.N, sparse=True))