def test_krotov_objective_initialization(transmon_ham_and_states): """Test basic instantiation of a krotov.Objective with qutip objects""" H, psi0, psi1 = transmon_ham_and_states obj = krotov.Objective(initial_state=psi0, target=psi1, H=H) assert obj.H == H assert obj.initial_state == psi0 assert obj.target == psi1 assert obj == krotov.Objective(H=H, initial_state=psi0, target=psi1)
def test_gate_objectives_single_qubit_gate(): """Test initialization of objectives for simple single-qubit gate""" basis = [ket([0]), ket([1])] gate = sigmay() # = -i|0⟩⟨1| + i|1⟩⟨0| H = [sigmaz(), [sigmax(), lambda t, args: 1.0]] objectives = krotov.objectives.gate_objectives(basis, gate, H) assert objectives == [ krotov.Objective(initial_state=basis[0], target=(1j * basis[1]), H=H), krotov.Objective(initial_state=basis[1], target=(-1j * basis[0]), H=H), ]
def test_extract_controls(): """Check that we can extract a list of controls from a list of objectives""" # dummy objects X = qutip.Qobj() Y = qutip.Qobj() f = lambda t: 0 g = lambda t: 0 h = lambda t: 0 d = lambda t: 0 # all of these dummy objects should be distinguishable assert f is not g assert g is not h assert h is not d assert X is not Y H1 = [X, [X, f], [X, g]] H2 = [X, [X, f], [X, h]] H3 = [X, [X, d], X] # check same Hamiltonian occuring in multiple objectives objectives = [ krotov.Objective(initial_state=X, target=Y, H=H1), krotov.Objective(initial_state=Y, target=X, H=H1), ] controls = extract_controls(objectives) maps = extract_controls_mapping(objectives, controls) assert len(controls) == 2 assert f in controls assert g in controls assert len(maps) == len(objectives) assert maps == [[[[1], [2]]], [[[1], [2]]]] # check same control occuring in multiple Hamiltonians objectives = [ krotov.Objective(initial_state=X, target=Y, H=H1), krotov.Objective(initial_state=Y, target=X, H=H2), krotov.Objective(initial_state=Y, target=X, H=H3), ] controls = extract_controls(objectives) assert len(controls) == 4 for c in (f, g, h, d): assert c in controls maps = extract_controls_mapping(objectives, controls) assert maps[0] == [[[1], [2], [], []]] assert maps[1] == [[[1], [], [2], []]] assert maps[2] == [[[], [], [], [1]]]
def test_ensemble_objectives(transmon_ham_and_states): """Test creation of ensemble objectives""" H, psi0, psi1 = transmon_ham_and_states objectives = [ krotov.Objective(initial_state=psi0, target=psi1, H=H), krotov.Objective(initial_state=psi1, target=psi0, H=H), ] (H0, (H1, eps)) = H Hs = [[H0, [mu * H1, eps]] for mu in [0.95, 0.99, 1.01, 1.05]] ensemble_objectives = krotov.ensemble_objectives(objectives, Hs) assert len(ensemble_objectives) == 10 assert ensemble_objectives[0] == objectives[0] assert ensemble_objectives[1] == objectives[1] assert (ensemble_objectives[2].H[1][0] - (0.95 * H1)).norm() < 1e-15 assert (ensemble_objectives[9].H[1][0] - (1.05 * H1)).norm() < 1e-15
def simple_state_to_state_system(): """System from 01_example_simple_state_to_state.ipynb""" omega = 1.0 ampl0 = 0.2 H0 = -0.5 * omega * qutip.operators.sigmaz() H1 = qutip.operators.sigmax() eps0 = lambda t, args: ampl0 H = [H0, [H1, eps0]] psi0 = qutip.ket('0') psi1 = qutip.ket('1') objectives = [krotov.Objective(initial_state=psi0, target=psi1, H=H)] def S(t): """Shape function for the field update""" return krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' ) pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S)} tlist = np.linspace(0, 5, 500) return objectives, pulse_options, tlist
def test_gate_objectives_pe(): """Test gate objectives for a PE optimization""" from qutip import ket, tensor, sigmaz, sigmax, identity from weylchamber import bell_basis basis = [ket(n) for n in [(0, 0), (0, 1), (1, 0), (1, 1)]] H = [ tensor(sigmaz(), identity(2)) + tensor(identity(2), sigmaz()), [tensor(sigmax(), identity(2)), lambda t, args: 1.0], [tensor(identity(2), sigmax()), lambda t, args: 1.0], ] objectives = krotov.gate_objectives(basis, 'PE', H) assert len(objectives) == 4 bell_basis_states = bell_basis(basis) for state in bell_basis_states: assert isinstance(state, qutip.Qobj) for i in range(4): expected_objective = krotov.Objective( initial_state=bell_basis_states[i], target='PE', H=H ) assert objectives[i] == expected_objective assert krotov.gate_objectives(basis, 'perfect_entangler', H) == objectives assert krotov.gate_objectives(basis, 'perfect entangler', H) == objectives assert krotov.gate_objectives(basis, 'Perfect Entangler', H) == objectives with pytest.raises(ValueError): krotov.gate_objectives(basis, 'prefect(!) entanglers', H)
def test_objective_mesolve_propagate(transmon_ham_and_states, tlist_control): """Test propagation method of objective""" tlist, control = tlist_control H, psi0, psi1 = transmon_ham_and_states H = copy.deepcopy(H) T = tlist[-1] nt = len(tlist) H[1][1] = lambda t, args: ( 0 if (t > float(T)) else control[int(round(float(nt-1) * (t/float(T))))]) target = krotov.Objective(H, psi0, psi1) assert len(tlist) == len(control) > 0 res1 = target.mesolve(tlist) res2 = target.propagate(tlist, propagator=krotov.propagators.expm) assert len(res1.states) == len(res2.states) == len(tlist) assert (1 - np.abs(res1.states[-1].overlap(res2.states[-1]))) < 1e-4 P0 = psi0 * psi0.dag() P1 = psi1 * psi1.dag() e_ops = [P0, P1] res1 = target.mesolve(tlist, e_ops=e_ops) res2 = target.propagate( tlist, e_ops=e_ops, propagator=krotov.propagators.expm) assert len(res1.states) == len(res2.states) == 0 assert len(res1.expect) == len(res2.expect) == 2 assert len(res1.expect[0]) == len(res2.expect[0]) == len(tlist) assert len(res1.expect[1]) == len(res2.expect[1]) == len(tlist) assert abs(res1.expect[0][-1] - res2.expect[0][-1]) < 1e-2 assert abs(res1.expect[1][-1] - res2.expect[1][-1]) < 1e-2 assert abs(res1.expect[0][-1] - 0.1925542) < 1e-7 assert abs(res1.expect[1][-1] - 0.7595435) < 1e-7
def test_objective_copy(transmon_ham_and_states): """Test that copy.copy(objective) produces the expected equalities by value and by reference""" H, psi0, psi1 = transmon_ham_and_states c1 = H[1].copy() # we just need something structurally sound ... c2 = H[1].copy() # ... It doesn't need to make sense physically assert c1 == c2 # equal by value assert c1 is not c2 # not equal by reference target1 = krotov.Objective( initial_state=psi0, target=psi1, H=H, c_ops=[c1, c2] ) target2 = copy.copy(target1) assert target1 == target2 assert target1 is not target2 assert target1.H == target2.H assert target1.H is not target2.H assert target1.H[0] is target2.H[0] assert target1.H[1] is not target2.H[1] assert target1.H[1][0] is target2.H[1][0] assert target1.H[1][1] is target2.H[1][1] assert target1.c_ops[0] == target2.c_ops[0] assert target1.c_ops[0] is not target2.c_ops[0] assert target1.c_ops[0][0] is target2.c_ops[0][0] assert target1.c_ops[0][1] is target2.c_ops[0][1] target1.weight = 0.5 target1.xxx = 'something' target2 = copy.copy(target1) assert hasattr(target2, 'weight') assert hasattr(target2, 'xxx') assert target1 == target2
def test_infohook_chaining(transmon_ham_and_states): """Test that transmon_ham_and_states and info_hooks get chained together correctly. This tests a whole bunch of implementation details: - return values from multiple info_hooks combine in tuple - return value None (from modify_params_after_iter) gets ignored - shared_data gets passed along through multiple hooks - shared_data is cleared in each iteration """ H, psi0, psi1 = transmon_ham_and_states obj = krotov.Objective(initial_state=psi0, target=psi1, H=H) tlist = np.array([0, 0.01, 0.02]) pulse_options = {H[1][1]: dict(lambda_a=1, update_shape=1)} stdout = io.StringIO() def adjust_lambda_a(**args): λₐ = args['lambda_vals'][0] args['lambda_vals'][0] *= 0.5 if 'messages' not in args['shared_data']: args['shared_data']['messages'] = [] args['shared_data']['messages'].append( 'λₐ: %s → %s' % (λₐ, args['lambda_vals'][0]) ) def print_fidelity(**args): F_re = np.average(np.array(args['tau_vals']).real) print("Iteration %d: \tF = %f" % (args['iteration'], F_re)) return F_re def print_messages(**args): if 'messages' in args['shared_data']: message = "; ".join( [msg for msg in args['shared_data']['messages']] ) print("\tmsg: " + message) return message with contextlib.redirect_stdout(stdout): oct_result = krotov.optimize_pulses( [obj], pulse_options=pulse_options, tlist=tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_re, info_hook=krotov.info_hooks.chain(print_fidelity, print_messages), modify_params_after_iter=adjust_lambda_a, iter_stop=2, ) assert len(oct_result.info_vals) == 3 assert isinstance(oct_result.info_vals[1], tuple) assert len(oct_result.info_vals[1]) == 2 assert abs(oct_result.info_vals[1][0] - 0.001978333994757067) < 1e-8 assert oct_result.info_vals[1][1] == 'λₐ: 0.5 → 0.25' assert 'Iteration 0: \tF = 0.000000' in stdout.getvalue() assert 'msg: λₐ: 1.0 → 0.5' in stdout.getvalue() assert 'Iteration 1: \tF = 0.001978' in stdout.getvalue() assert 'msg: λₐ: 0.5 → 0.25' in stdout.getvalue()
def test_initialize_krotov_controls(): """Check that pulses and controls are initialized while preserving the correct boundary conditions. This is the point that the section "Time Discretization Schemes" in the documentation is making. Tests the resolution of #20. """ T = 10 blackman = qutip_callback(krotov.shapes.blackman, t_start=0, t_stop=T) H = ['H0', ['H1', blackman]] tlist = np.linspace(0, T, 10) pulse_options = {blackman: dict(lambda_a=1.0, update_shape=1)} objectives = [ krotov.Objective(initial_state=qutip.Qobj(), target=None, H=H) ] assert abs(blackman(0, None)) < 1e-15 assert abs(blackman(T, None)) < 1e-15 ( guess_controls, guess_pulses, pulses_mapping, lambda_vals, shape_arrays, ) = krotov.optimize._initialize_krotov_controls( objectives, pulse_options, tlist ) assert isinstance(guess_controls[0], np.ndarray) assert len(guess_controls[0]) == len(tlist) assert abs(guess_controls[0][0]) < 1e-15 assert abs(guess_controls[0][-1]) < 1e-15 assert isinstance(guess_pulses[0], np.ndarray) assert len(guess_pulses[0]) == len(tlist) - 1 assert abs(guess_pulses[0][0]) < 1e-15 assert abs(guess_pulses[0][-1]) < 1e-15 assert len(pulse_options) == 1 assert len(pulses_mapping) == 1 assert len(pulses_mapping[0]) == 1 assert len(pulses_mapping[0][0]) == 1 assert len(pulses_mapping[0][0][0]) == 1 assert pulses_mapping[0][0][0][0] == 1 assert len(lambda_vals) == 1 assert lambda_vals[0] == 1.0 assert len(shape_arrays) == 1 assert isinstance(shape_arrays[0], np.ndarray) assert len(shape_arrays[0]) == len(tlist) - 1
def test_adoint_objective_with_no_target(transmon_ham_and_states): """Test taking the adjoint of an objective if target is None""" H, psi0, _ = transmon_ham_and_states target = krotov.Objective(initial_state=psi0, target=None, H=H) adjoint_target = target.adjoint() assert (adjoint_target.H[0] - target.H[0]).norm() < 1e-12 assert (adjoint_target.H[1][0] - target.H[1][0]).norm() < 1e-12 assert adjoint_target.H[1][1] == target.H[1][1] assert adjoint_target.initial_state.isbra assert adjoint_target.target is None
def tls_control_system_tdcops(tls_control_system): """Control system with time-dependent collapse operators""" objectives, controls, _ = tls_control_system c_op = [[0.1 * sigmap(), controls[0]]] c_ops = [c_op] H1 = objectives[0].H H2 = objectives[1].H objectives = [ krotov.Objective( initial_state=ket('0'), target=ket('1'), H=H1, c_ops=c_ops ), krotov.Objective( initial_state=ket('0'), target=ket('1'), H=H2, c_ops=c_ops ), ] controls_mapping = krotov.conversions.extract_controls_mapping( objectives, controls ) return objectives, controls, controls_mapping
def tls_control_system(): """Non-trivial control system defined on a TLS""" eps1 = lambda t, args: 0.5 eps2 = lambda t, args: 1 H1 = [0.5 * sigmaz(), [sigmap(), eps1], [sigmam(), eps1]] H2 = [0.5 * sigmaz(), [sigmaz(), eps2]] c_ops = [0.1 * sigmap()] objectives = [ krotov.Objective( initial_state=ket('0'), target=ket('1'), H=H1, c_ops=c_ops ), krotov.Objective( initial_state=ket('0'), target=ket('1'), H=H2, c_ops=c_ops ), ] controls = [eps1, eps2] controls_mapping = krotov.conversions.extract_controls_mapping( objectives, controls ) return objectives, controls, controls_mapping
def test_extract_controls_with_arrays(): """Test extract_controls for controls that are numpy arrays""" X, Y, Z = qutip.Qobj(), qutip.Qobj(), qutip.Qobj() # dummy Hamiltonians u1, u2 = np.array([]), np.array([]) # dummy controls psi0, psi_tgt = qutip.Qobj(), qutip.Qobj() # dummy states assert X is not Y assert Y is not Z assert u1 is not u2 assert psi0 is not psi_tgt H1 = [X, [Y, u1], [Z, u2]] # ham for first objective H2 = [X, [Y, u2]] # ham for second objective objectives = [ krotov.Objective(H1, psi0, psi_tgt), krotov.Objective(H2, psi0, psi_tgt)] controls = extract_controls(objectives) control_map = extract_controls_mapping(objectives, controls) assert controls == [u1, u2] assert control_map[0] == [[[1], [2]]] assert control_map[1] == [[[], [1]]]
def test_adoint_objective(transmon_ham_and_states): """Test taking the adjoint of an objective""" H, psi0, psi1 = transmon_ham_and_states target = krotov.Objective(H, psi0, psi1) adjoint_target = target.adjoint assert isinstance(adjoint_target.H, list) assert isinstance(adjoint_target.H[0], qutip.Qobj) assert isinstance(adjoint_target.H[1], list) assert isinstance(adjoint_target.H[1][0], qutip.Qobj) assert (adjoint_target.H[0] - target.H[0]).norm() < 1e-12 assert (adjoint_target.H[1][0] - target.H[1][0]).norm() < 1e-12 assert adjoint_target.H[1][1] == target.H[1][1] assert adjoint_target.initial_state.isbra assert adjoint_target.target_state.isbra
def numpy_control_system(): """Optimization system for State-to-State Transfer This is the same as in 01_example_simple_state_to_state.ipynb, but using a numpy array as the control. """ tlist = np.linspace(0, 5, 500) def hamiltonian(omega=1.0, ampl0=0.2): """Two-level-system Hamiltonian Args: omega (float): energy separation of the qubit levels ampl0 (float): constant amplitude of the driving field """ H0 = -0.5 * omega * qutip.operators.sigmaz() H1 = qutip.operators.sigmax() def guess_control(t, args): return ampl0 * krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, func="blackman") guess_array = np.array([guess_control(t, []) for t in tlist]) # return [H0, [H1, guess_control]] return [H0, [H1, guess_array]] H = hamiltonian() objectives = [ krotov.Objective( initial_state=qutip.ket("0"), target=qutip.ket("1"), H=H, ) ] def S(t): """Shape function for the field update""" return krotov.shapes.flattop(t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='blackman') # pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S)} pulse_options = {id(H[1][1]): dict(lambda_a=5, update_shape=S)} return tlist, objectives, pulse_options
def objective_liouville(): a1 = np.random.random(100) + 1j * np.random.random(100) a2 = np.random.random(100) + 1j * np.random.random(100) H = [ tensor(sigmaz(), identity(2)) + tensor(identity(2), sigmaz()), [tensor(sigmax(), identity(2)), a1], [tensor(identity(2), sigmax()), a2], ] L = krotov.objectives.liouvillian(H, c_ops=[]) ket00 = ket((0, 0)) ket11 = ket((1, 1)) obj = krotov.Objective( initial_state=qutip.ket2dm(ket00), target=qutip.ket2dm(ket11), H=L ) return obj
def objective_with_c_ops(): u1 = lambda t, args: 1.0 u2 = lambda t, args: 1.0 a1 = np.random.random(100) + 1j * np.random.random(100) a2 = np.random.random(100) + 1j * np.random.random(100) H = [ tensor(sigmaz(), identity(2)) + tensor(identity(2), sigmaz()), [tensor(sigmax(), identity(2)), u1], [tensor(identity(2), sigmax()), u2], ] C1 = [[tensor(identity(2), sigmap()), a1]] C2 = [[tensor(sigmap(), identity(2)), a2]] ket00 = ket((0, 0)) ket11 = ket((1, 1)) obj = krotov.Objective( initial_state=ket00, target=ket11, H=H, c_ops=[C1, C2] ) return obj
def test_discretization_as_float(): """"Test that a control function that returns an int still gets discretized as a float (#41)""" H = [qutip.Qobj(), [qutip.Qobj(), lambda t, args: 0]] u = H[1][1] objectives = [ krotov.Objective(initial_state=qutip.Qobj(), target=None, H=H) ] tlist = np.linspace(0, 10, 100) res = krotov.optimize._initialize_krotov_controls( objectives, {u: dict(lambda_a=1, update_shape=lambda t: 0)}, tlist) guess_controls = res[0] assert guess_controls[0].dtype == np.float64 guess_pulses = res[1] assert guess_pulses[0].dtype == np.float64 shape_arrays = res[4] assert shape_arrays[0].dtype == np.float64
def test_complex_control_rejection(): """Test that complex controls are rejected""" H0 = qutip.Qobj(0.5 * np.diag([-1, 1])) H1 = qutip.Qobj(np.mat([[1, 2], [3, 4]])) psi0 = qutip.Qobj(np.array([1, 0])) psi1 = qutip.Qobj(np.array([0, 1])) def eps0(t, args): return 0.2 * np.exp(1j * t) def S(t): """Shape function for the field update""" return krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' ) H = [H0, [H1, eps0]] objectives = [krotov.Objective(initial_state=psi0, target=psi1, H=H)] pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S)} tlist = np.linspace(0, 5, 500) with pytest.raises(ValueError) as exc_info: krotov.optimize_pulses( objectives, pulse_options, tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_re, iter_stop=0, ) assert 'all controls must be real-valued' in str(exc_info.value) def S2(t): """Shape function for the field update""" return 2.0 * krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' )
def test_adoint_objective(transmon_ham_and_states, objective_with_c_ops): """Test taking the adjoint of an objective""" H, psi0, psi1 = transmon_ham_and_states target = krotov.Objective(initial_state=psi0, target=psi1, H=H) adjoint_target = target.adjoint() assert isinstance(adjoint_target.H, list) assert isinstance(adjoint_target.H[0], qutip.Qobj) assert isinstance(adjoint_target.H[1], list) assert isinstance(adjoint_target.H[1][0], qutip.Qobj) assert (adjoint_target.H[0] - target.H[0]).norm('max') < 1e-12 assert (adjoint_target.H[1][0] - target.H[1][0]).norm('max') < 1e-12 assert adjoint_target.H[1][1] == target.H[1][1] assert adjoint_target.initial_state.isbra assert adjoint_target.target.isbra # also try something that has numpy arrays obj = objective_with_c_ops obj_dag = obj.adjoint() δ = (obj_dag.c_ops[0][0][0].dag() - obj.c_ops[0][0][0]).norm('max') assert δ < 1e-12 assert isinstance(obj_dag.c_ops[0][0][1], np.ndarray) assert np.array_equal(obj_dag.c_ops[0][0][1], obj.c_ops[0][0][1])
def test_invalid_objective(transmon_ham_and_states): """Test that invalid objectives raise a ValueError""" H, psi0, psi1 = transmon_ham_and_states with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=psi0.full, target=psi1, H=H) assert "Invalid initial_state" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=None, target=psi1, H=H) assert "Invalid initial_state" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=psi0, target=psi1, H=tuple(H)) assert "Invalid H" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=psi0, target=psi1, H=None) assert "Invalid H" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=psi0, target=psi1, H=H[0].full) assert "Invalid H" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: krotov.Objective(initial_state=psi0, target=psi1, H=H, c_ops=H[0]) assert "Invalid c_ops" in str(exc_info.value)
norm_V = C6 / (LATTICE_SPACING ** 6) / characteristic_V norm_Omega_t, norm_Omega = np.array(Omega[0]) * characteristic_V, np.array(Omega[1]) / characteristic_V norm_Delta_t, norm_Delta = np.array(Delta[0]) * characteristic_V, np.array(Delta[1]) / characteristic_V norm_t = t * characteristic_V norm_H_d, norm_H_c, psi_0 = get_normalised_hamiltonian(N, norm_V) target_state = StandardGHZState(N).get_state_tensor(GHZ_SYMMETRIC) norm_t_list: np.ndarray = np.linspace(0, norm_t, 500) H = [norm_H_d, [norm_H_c[0], lambda t, args: 1], [norm_H_c[1], lambda t, args: 0.1]] objectives = [ krotov.Objective(initial_state=psi_0, target=target_state, H=H) ] def S(t): """Shape function for the field update""" return krotov.shapes.flattop(t, t_start=0, t_stop=norm_t, t_rise=norm_t / 10, t_fall=norm_t / 10, func='sinsq') def shape_field(eps0): """Applies the shape function S(t) to the guess field""" eps0_shaped = lambda t, args: eps0(t, args)*S(t) return eps0_shaped # H[1][1] = shape_field(H[1][1])
EEnergy[i] = (np.square(EField[i]) + a) * (T / nt) ax.plot(tlist, np.transpose(EEnergy)) plt.legend() plt.show(fig) fig.savefig('Energyofthefield6cells-nodissipation.png') H = hamiltonian(omega, ampl0, g) pulse_options = {H[1][1]: dict(lambda_a=0.25, update_shape=S)} objectives = [ krotov.Objective(initial_state=qutip.tensor(qutip.ket("0"), qutip.ket("0"), qutip.ket("0"), qutip.ket("0"), qutip.ket("0"), qutip.ket("0"), qutip.ket("0")), target=qutip.tensor(qutip.ket("0"), qutip.ket("1"), qutip.ket("1"), qutip.ket("1"), qutip.ket("1"), qutip.ket("1"), qutip.ket("1")), H=H) ] opt_result = krotov.optimize_pulses( objectives, pulse_options=pulse_options, tlist=tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_ss, info_hook=krotov.info_hooks.print_table(J_T=krotov.functionals.J_T_ss), check_convergence=krotov.convergence.Or( krotov.convergence.value_below('5e-3', name='J_T'),
rho_q_trg = qutip.Qobj(np.diag([1, 0])) rho_T_trg = qutip.tensor(qutip.Qobj(np.diag([0, 1])), qutip.Qobj(np.diag([0, 1])), qutip.Qobj(np.diag([0, 1])), qutip.Qobj(np.diag([0, 1])), qutip.Qobj(np.diag([0, 1])), qutip.Qobj(np.diag([0, 1]))) rho_trg = qutip.tensor(rho_q_trg, rho_T_trg) rho_trg = qutip.Qobj(rho_trg) print(rho_trg) """Next, the list of `objectives` is defined, which contains the initial and target state and the Liouvillian $\Liouville(t)$ that determines the system dynamics. """ objectives = [krotov.Objective(initial_state=rho_th, target=rho_trg, H=L)] """In the following, we define the shape function $S(t)$, which we use in order to ensure a smooth switch on and off in the beginning and end. Note that at times $t$ where $S(t)$ vanishes, the updates of the field is suppressed. """ def S(t): """Shape function for the field update""" return krotov.shapes.flattop(t, t_start=0, t_stop=T, t_rise=0.005 * T, t_fall=0.005 * T, func='sinsq')
def test_reject_invalid_shapes(): """Test that invalid control shapes are rejected""" H0 = qutip.Qobj(0.5 * np.diag([-1, 1])) H1 = qutip.Qobj(np.mat([[1, 2], [3, 4]])) psi0 = qutip.Qobj(np.array([1, 0])) psi1 = qutip.Qobj(np.array([0, 1])) def eps0(t, args): return 0.2 H = [H0, [H1, eps0]] objectives = [krotov.Objective(initial_state=psi0, target=psi1, H=H)] tlist = np.linspace(0, 5, 500) def S_complex(t): """Shape function for the field update""" return 1j * krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' ) def S_negative(t): """Shape function for the field update""" return -1 * krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' ) def S_large(t): """Shape function for the field update""" return 2 * krotov.shapes.flattop( t, t_start=0, t_stop=5, t_rise=0.3, t_fall=0.3, func='sinsq' ) with pytest.raises(ValueError) as exc_info: pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S_complex)} krotov.optimize_pulses( objectives, pulse_options, tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_re, iter_stop=0, ) assert 'must be real-valued' in str(exc_info.value) with pytest.raises(ValueError) as exc_info: pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S_negative)} krotov.optimize_pulses( objectives, pulse_options, tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_re, iter_stop=0, ) assert 'must have values in the range [0, 1]' in str(exc_info.value) with pytest.raises(ValueError) as exc_info: pulse_options = {H[1][1]: dict(lambda_a=5, update_shape=S_large)} krotov.optimize_pulses( objectives, pulse_options, tlist, propagator=krotov.propagators.expm, chi_constructor=krotov.functionals.chis_re, iter_stop=0, ) assert 'must have values in the range [0, 1]' in str(exc_info.value)
def test_shape_validation(): """Test that OCT pulse shapes are converted and verified correctly""" H = [qutip.Qobj(), [qutip.Qobj(), lambda t, args: 0]] u = H[1][1] objectives = [ krotov.Objective(initial_state=qutip.Qobj(), target=None, H=H) ] tlist = np.linspace(0, 10, 100) res = _initialize_krotov_controls(objectives, {u: dict(lambda_a=1, update_shape=1)}, tlist) # res consists of: # guess_controls, guess_pulses, pulses_mapping, lambda_vals, shape_arrays shape_arrays = res[4] shape_array = shape_arrays[0] assert len(shape_arrays) == 1 assert len(shape_array) == len(tlist) - 1 assert np.all(shape_array == 1) lambda_vals = res[3] assert len(lambda_vals) == 1 assert lambda_vals[0] == 1 assert isinstance(lambda_vals[0], float) res = _initialize_krotov_controls(objectives, {u: dict(lambda_a=1, update_shape=0)}, tlist) shape_array = res[4][0] assert np.all(shape_array == 0) with pytest.raises(ValueError) as exc_info: _initialize_krotov_controls(objectives, {u: dict(lambda_a=1)}, tlist) assert "key 'update_shape'" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: _initialize_krotov_controls(objectives, {u: { 'update_shape': 1 }}, tlist) assert "key 'lambda_a'" in str(exc_info.value) with pytest.raises(ValueError) as exc_info: _initialize_krotov_controls(objectives, {u: dict(lambda_a=1, update_shape=2)}, tlist) assert 'update_shape must be a callable' in str(exc_info.value) with pytest.raises(ValueError) as exc_info: _initialize_krotov_controls( objectives, {u: dict(lambda_a=1, update_shape=lambda t: 2.0)}, tlist, ) assert 'in the range [0, 1]' in str(exc_info.value) with pytest.raises(ValueError) as exc_info: _initialize_krotov_controls( objectives, {u: dict(lambda_a=1, update_shape=lambda t: 0.5j)}, tlist, ) assert 'real-valued' in str(exc_info.value)