def cy_grape_unitary( U, H0, H_ops, R, times, eps=None, u_start=None, u_limits=None, interp_kind="linear", use_interp=False, alpha=None, beta=None, phase_sensitive=True, progress_bar=BaseProgressBar(), ): """ Calculate control pulses for the Hamitonian operators in H_ops so that the unitary U is realized. Experimental: Work in progress. Parameters ---------- U : Qobj Target unitary evolution operator. H0 : Qobj Static Hamiltonian (that cannot be tuned by the control fields). H_ops: list of Qobj A list of operators that can be tuned in the Hamiltonian via the control fields. R : int Number of GRAPE iterations. time : array / list Array of time coordinates for control pulse evalutation. u_start : array Optional array with initial control pulse values. Returns ------- Instance of GRAPEResult, which contains the control pulses calculated with GRAPE, a time-dependent Hamiltonian that is defined by the control pulses, as well as the resulting propagator. """ if eps is None: eps = 0.1 * (2 * np.pi) / (times[-1]) M = len(times) J = len(H_ops) u = np.zeros((R, J, M)) H_ops_data = [H_op.data for H_op in H_ops] if u_limits and len(u_limits) != 2: raise ValueError("u_limits must be a list with two values") if u_limits: warnings.warn("Causion: Using experimental feature u_limits") if u_limits and u_start: # make sure that no values in u0 violates the u_limits conditions u_start = np.array(u_start) u_start[u_start < u_limits[0]] = u_limits[0] u_start[u_start > u_limits[1]] = u_limits[1] if u_limits: use_u_limits = 1 u_min = u_limits[0] u_max = u_limits[1] else: use_u_limits = 0 u_min = 0.0 u_max = 0.0 if u_start is not None: for idx, u0 in enumerate(u_start): u[0, idx, :] = u0 if beta: warnings.warn("Causion: Using experimental feature time-penalty") alpha_val = alpha if alpha else 0.0 beta_val = beta if beta else 0.0 progress_bar.start(R) for r in range(R - 1): progress_bar.update(r) dt = times[1] - times[0] if use_interp: ip_funcs = [ interp1d(times, u[r, j, :], kind=interp_kind, bounds_error=False, fill_value=u[r, j, -1]) for j in range(J) ] def _H_t(t, args=None): return H0 + sum([float(ip_funcs[j](t)) * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_t(times[idx]) * dt).expm().data for idx in range(M - 1)] else: def _H_idx(idx): return H0 + sum([u[r, j, idx] * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_idx(idx) * dt).expm().data for idx in range(M - 1)] U_f_list = [] U_b_list = [] U_f = 1 U_b = sp.eye(*(U.shape)) for n in range(M - 1): U_f = U_list[n] * U_f U_f_list.append(U_f) U_b_list.insert(0, U_b) U_b = U_list[M - 2 - n].T.conj().tocsr() * U_b cy_grape_inner( U.data, u, r, J, M, U_b_list, U_f_list, H_ops_data, dt, eps, alpha_val, beta_val, phase_sensitive, use_u_limits, u_min, u_max, ) if use_interp: ip_funcs = [ interp1d(times, u[R - 1, j, :], kind=interp_kind, bounds_error=False, fill_value=u[R - 1, j, -1]) for j in range(J) ] H_td_func = [H0] + [[H_ops[j], lambda t, args, j=j: ip_funcs[j](t)] for j in range(J)] else: H_td_func = [H0] + [[H_ops[j], u[-1, j, :]] for j in range(J)] progress_bar.finished() return GRAPEResult(u=u, U_f=Qobj(U_f_list[-1], dims=U.dims), H_t=H_td_func)
def cy_grape_unitary(U, H0, H_ops, R, times, eps=None, u_start=None, u_limits=None, interp_kind='linear', use_interp=False, alpha=None, beta=None, phase_sensitive=True, progress_bar=BaseProgressBar()): """ Calculate control pulses for the Hamitonian operators in H_ops so that the unitary U is realized. Experimental: Work in progress. Parameters ---------- U : Qobj Target unitary evolution operator. H0 : Qobj Static Hamiltonian (that cannot be tuned by the control fields). H_ops: list of Qobj A list of operators that can be tuned in the Hamiltonian via the control fields. R : int Number of GRAPE iterations. time : array / list Array of time coordinates for control pulse evalutation. u_start : array Optional array with initial control pulse values. Returns ------- Instance of GRAPEResult, which contains the control pulses calculated with GRAPE, a time-dependent Hamiltonian that is defined by the control pulses, as well as the resulting propagator. """ if eps is None: eps = 0.1 * (2 * np.pi) / (times[-1]) M = len(times) J = len(H_ops) u = np.zeros((R, J, M)) H_ops_data = [H_op.data for H_op in H_ops] if u_limits and len(u_limits) != 2: raise ValueError("u_limits must be a list with two values") if u_limits: warnings.warn("Causion: Using experimental feature u_limits") if u_limits and u_start: # make sure that no values in u0 violates the u_limits conditions u_start = np.array(u_start) u_start[u_start < u_limits[0]] = u_limits[0] u_start[u_start > u_limits[1]] = u_limits[1] if u_limits: use_u_limits = 1 u_min = u_limits[0] u_max = u_limits[1] else: use_u_limits = 0 u_min = 0.0 u_max = 0.0 if u_start is not None: for idx, u0 in enumerate(u_start): u[0, idx, :] = u0 if beta: warnings.warn("Causion: Using experimental feature time-penalty") alpha_val = alpha if alpha else 0.0 beta_val = beta if beta else 0.0 progress_bar.start(R) for r in range(R - 1): progress_bar.update(r) dt = times[1] - times[0] if use_interp: ip_funcs = [ interp1d(times, u[r, j, :], kind=interp_kind, bounds_error=False, fill_value=u[r, j, -1]) for j in range(J) ] def _H_t(t, args=None): return H0 + sum( [float(ip_funcs[j](t)) * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_t(times[idx]) * dt).expm().data for idx in range(M - 1)] else: def _H_idx(idx): return H0 + sum([u[r, j, idx] * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_idx(idx) * dt).expm().data for idx in range(M - 1)] U_f_list = [] U_b_list = [] U_f = 1 U_b = sp.eye(*(U.shape)) for n in range(M - 1): U_f = U_list[n] * U_f U_f_list.append(U_f) U_b_list.insert(0, U_b) U_b = U_list[M - 2 - n].T.conj().tocsr() * U_b cy_grape_inner(U.data, u, r, J, M, U_b_list, U_f_list, H_ops_data, dt, eps, alpha_val, beta_val, phase_sensitive, use_u_limits, u_min, u_max) if use_interp: ip_funcs = [ interp1d(times, u[R - 1, j, :], kind=interp_kind, bounds_error=False, fill_value=u[R - 1, j, -1]) for j in range(J) ] H_td_func = [H0] + [[H_ops[j], lambda t, args, j=j: ip_funcs[j](t)] for j in range(J)] else: H_td_func = [H0] + [[H_ops[j], u[-1, j, :]] for j in range(J)] progress_bar.finished() return GRAPEResult(u=u, U_f=Qobj(U_f_list[-1], dims=U.dims), H_t=H_td_func)