Example #1
0
    def test_quasi_static_noise_monte_carlo(self):
        np.random.seed(0)
        h_ctrl = [
            DenseOperator(np.diag([.5, -.5])),
        ]
        h_drift = [DenseOperator(np.zeros((2, 2)))]

        n_noise_values = 20
        noise_levels = 1e-4 * np.arange(1, n_noise_values + 1)
        actual_noise_levels = np.zeros((n_noise_values, ))
        average_infids = np.zeros((n_noise_values, ))

        for i, std_dev in enumerate(noise_levels):
            ntg = NTGQuasiStatic(standard_deviation=[
                std_dev,
            ],
                                 n_samples_per_trace=1,
                                 n_traces=2000,
                                 sampling_mode='monte_carlo')

            ctrl_amps = 2 * np.pi * np.ones((1, 1)) * 0
            t_slot_comp = SchroedingerSMonteCarlo(h_drift=h_drift,
                                                  h_ctrl=h_ctrl,
                                                  initial_state=DenseOperator(
                                                      np.eye(2)),
                                                  tau=[1],
                                                  h_noise=h_ctrl,
                                                  noise_trace_generator=ntg)
            t_slot_comp.set_optimization_parameters(ctrl_amps)

            quasi_static_infid = OperationNoiseInfidelity(
                solver=t_slot_comp,
                target=DenseOperator(np.eye(2)),
                neglect_systematic_errors=False,
                fidelity_measure='entanglement')
            average_infids[i] = quasi_static_infid.costs() * (2 / 3)
            actual_noise_levels[i] = np.std(ntg.noise_samples)

        self.assertLess(
            np.sum(
                np.abs((np.ones_like(average_infids) - average_infids /
                        (noise_levels**2 / 6)))) / 100, 0.05)
        self.assertLess(
            np.sum(
                np.abs((np.ones_like(average_infids) - average_infids /
                        (actual_noise_levels**2 / 6)))) / 100, 0.05)
Example #2
0
    def test_quasi_static_noise_deterministic_sampling(self):
        """ The same problem has also been positively tested with two time
        steps. """
        h_ctrl = [
            DenseOperator(np.diag([.5, -.5])),
        ]
        h_drift = [DenseOperator(np.zeros((2, 2)))]

        noise_levels = 1e-4 * np.arange(1, 101)
        actual_noise_levels = np.zeros((100, ))
        average_infids = np.zeros((100, ))

        for i, std_dev in enumerate(noise_levels):
            ntg = NTGQuasiStatic(standard_deviation=[
                std_dev,
            ],
                                 n_samples_per_trace=1,
                                 n_traces=200,
                                 sampling_mode='uncorrelated_deterministic')

            ctrl_amps = 2 * np.pi * np.ones((1, 1))
            t_slot_comp = SchroedingerSMonteCarlo(h_drift=h_drift,
                                                  h_ctrl=h_ctrl,
                                                  initial_state=DenseOperator(
                                                      np.eye(2)),
                                                  tau=[1],
                                                  h_noise=h_ctrl,
                                                  noise_trace_generator=ntg)
            t_slot_comp.set_optimization_parameters(ctrl_amps)

            quasi_static_infid = OperationNoiseInfidelity(
                solver=t_slot_comp,
                target=DenseOperator(np.eye(2)),
                neglect_systematic_errors=True,
                fidelity_measure='entanglement')
            average_infids[i] = quasi_static_infid.costs() * (2 / 3)
            actual_noise_levels[i] = np.std(ntg.noise_samples)

        self.assertLess(
            np.sum(
                np.abs((np.ones_like(average_infids) - average_infids /
                        (noise_levels**2 / 6)))) / 100, 0.05)
        self.assertLess(
            np.sum(
                np.abs((np.ones_like(average_infids) - average_infids /
                        (actual_noise_levels**2 / 6)))) / 100, 1e-5)
Example #3
0
import numpy as np

from qopt.matrix import DenseOperator
from qopt.solver_algorithms import LindbladSolver
from qopt.cost_functions import OperationInfidelity
from qopt.simulator import Simulator

sigma_minus = DenseOperator(np.asarray([[0, 0], [1, 0]]))
zero_matrix = DenseOperator(np.asarray([[0, 0], [0, 0]]))
gamma = 3


def prefactor_function(control_amplitudes):
    return gamma * np.expand_dims(np.sum(np.abs(control_amplitudes), axis=1),
                                  axis=1)


def prefactor_function_derivative(control_amplitudes):
    return np.expand_dims(gamma * np.sign(control_amplitudes), axis=2)


solver = LindbladSolver(
    h_drift=[
        zero_matrix,
    ],
    h_ctrl=[zero_matrix, zero_matrix],
    initial_state=DenseOperator(np.eye(4)),
    tau=[
        1,
    ],
    lindblad_operators=[
Example #4
0
    def quasi_static_noise(self):

        sigma_z = DenseOperator(np.asarray([[1, 0], [0, -1]]))
        sigma_x = DenseOperator(np.asarray([[0, 1], [1, 0]]))
        h_drift = DenseOperator(np.zeros((2, 2)))

        # reference_frequency = 20e9 * 2 * np.pi
        reference_frequency = 100e6 * 2 * np.pi
        driving_frequency = 1e6 * 2 * np.pi

        # 100 per reference period
        # int(reference_frequency / driving_frequency) to make one driving period
        # 20 driving periods
        n_time_steps = int(35 * reference_frequency / driving_frequency * 20)
        n_noise_traces = 100  # int(10 * 60 * 1e6 / 35)
        evolution_time = 35e-6

        delta_t = evolution_time / n_time_steps

        down = np.asarray([[0], [1]])
        up = np.asarray([[1], [0]])
        x_half = rabi.x_half.data

        projector_left = up.T
        projector_right = up

        def up_amplitude(unitary):
            probability = projector_left @ unitary.data @ projector_right
            return np.abs(probability) ** 2

        ctrl_amps = delta_t * np.arange(1, 1 + n_time_steps)
        ctrl_amps = driving_frequency * np.sin(reference_frequency * ctrl_amps)


        def rabi_driving(transferred_parameters, **_):
            ctrl_amps = delta_t * np.arange(1, 1 + n_time_steps)
            ctrl_amps = 2 * np.sin(reference_frequency * ctrl_amps)
            # times 2 because the rabi frequency is .5 * Amplitude
            ctrl_amps = np.einsum("tc, t->tc", transferred_parameters, ctrl_amps)
            return ctrl_amps


        def rabi_driving_noise(noise_samples, **_):
            ctrl_amps = delta_t * np.arange(1, 1 + n_time_steps)
            ctrl_amps = 2 * np.sin(reference_frequency * ctrl_amps)
            ctrl_amps = np.einsum("sno, t->tno", noise_samples, ctrl_amps)
            return ctrl_amps


        rabi_driving_amp_func = CustomAmpFunc(value_function=rabi_driving,
                                              derivative_function=None)
        id_transfer_func = OversamplingTF(oversampling=n_time_steps)
        id_transfer_func.set_times(np.asarray([evolution_time]))


        ts_comp_unperturbed = SchroedingerSolver(
            h_drift=[reference_frequency * .5 * sigma_z, ] * n_time_steps,
            h_ctrl=[.5 * sigma_x, ],
            initial_state=DenseOperator(np.eye(2)),
            tau=[delta_t, ] * n_time_steps,
            exponential_method='Frechet',

        )

        ts_comp_lindblad = LindbladSolver(
            h_drift=[reference_frequency * .5 * sigma_z, ] * n_time_steps,
            h_ctrl=[.5 * sigma_x, ],
            initial_state=DenseOperator(np.eye(2)),
            tau=[delta_t, ] * n_time_steps,
            exponential_method='Frechet'
        )

        ts_comp_unperturbed.set_optimization_parameters(np.expand_dims(ctrl_amps, 1))


        """
        # unperturbed:
        forward_propagators = ts_comp_unperturbed.forward_propagators
        
        propabilities = np.zeros((n_time_steps, ))
        for j in range(n_time_steps):
            propabilities[j] = up_amplitude(forward_propagators[j])
        
        plt.figure()
        plt.plot(delta_t * np.arange(n_time_steps), propabilities)
        """

        # Tom
        # todo: he seems to assume angular frequencies in his spectrum
        S_01 = 3e8
        S_02 = 3e4
        # S(f) = S_01 / f + S_02 / f^2

        f_min = 1 / 10 / 60  # 1 over 10 minutes
        f_max = 1 / 35e-6

        variance_f = S_01 * (np.log(f_max) - np.log(f_min)) \
            - S_02 * (1 / f_max - 1 / f_min)
        sigma_f = np.sqrt(variance_f)


        """
        # Yoneda
        S_0 = 3.2 * 1e6 * 4 * np.pi * np.pi
        
        f_min = 1e-2
        f_max = 1 / 35e-6
        
        variance_f = S_0 * (np.log(f_max) - np.log(f_min))
        sigma_f = np.sqrt(variance_f)  # 29 kHz
        """
        expected_t2star = np.sqrt(2 / variance_f)

        ntg = NTGQuasiStatic(
            standard_deviation=[sigma_f, ],
            n_samples_per_trace=1,
            n_traces=n_noise_traces,
            always_redraw_samples=False,
            sampling_mode='monte_carlo'
        )


        tslot_comp = SchroedingerSMonteCarlo(
            h_drift=[reference_frequency * .5 * sigma_z, ] * n_time_steps,
            h_ctrl=[.5 * sigma_x, ],
            h_noise=[.5 * sigma_x],
            initial_state=DenseOperator(np.eye(2)),
            tau=[delta_t, ] * n_time_steps,
            noise_trace_generator=ntg,
            exponential_method='Frechet',
            transfer_function=id_transfer_func,
            amplitude_function=rabi_driving_amp_func,
            noise_amplitude_function=rabi_driving_noise
        )

        """
        # for the rotating frame
        delta_rabi = 1.5 / 10 * 1e6
        tslot_comp.set_optimization_parameters(
            (2 * np.pi * delta_rabi) * np.ones((n_time_steps, 1)))
        """
        tslot_comp.set_optimization_parameters(np.asarray([[driving_frequency]]))

        forward_propagators = tslot_comp.forward_propagators_noise

        propabilities = np.zeros((n_noise_traces, n_time_steps))
        for i in range(n_noise_traces):
            for j in range(n_time_steps):
                propabilities[i, j] = up_amplitude(forward_propagators[i][j])

        propabilities = np.mean(propabilities, axis=0)

        """
        def t2star_decay(t, delta_f, t2_star):
            return .5 * np.exp(-(t / t2_star) ** 2) * np.cos(
                2 * np.pi * delta_f * t) + .5
        """


        def t2star_decay(t, sigma_driving):
            return .5 * np.exp(-.5 * (sigma_driving * t) ** 2) * np.cos(driving_frequency * t) + .5


        def t2star_decay_2(t, sigma_driving):
            return .5 * (1 + (sigma_driving ** 2 / driving_frequency * t)) ** -.25 * np.cos(driving_frequency * t) + .5


        def t2star_decay_3(t, sigma_driving, sigma_ref):
            up_prop = np.exp(-.5 * (sigma_driving * t) ** 2)
            up_prop *= (1 + (sigma_ref ** 2 / driving_frequency * t) ** 2) ** -.25
            up_prop *= .5 * np.cos(driving_frequency * t)
            up_prop += .5
            return up_prop


        def t2star_decay_4(t, sigma_driving, sigma_ref, periodicity):
            up_prop = np.exp(-.5 * (sigma_driving * t) ** 2)
            up_prop *= (1 + ((sigma_ref ** 2) / periodicity * t) ** 2) ** -.25
            up_prop *= .5 * np.cos(periodicity * t)
            up_prop += .5
            return up_prop


        def t2star_decay_5(t, sigma_driving, sigma_ref, periodicity, lin_decay):
            up_prop = np.exp(-.5 * (sigma_driving * t) ** 2)
            up_prop *= np.exp(-1 * lin_decay * t)
            up_prop *= (1 + ((sigma_ref ** 2) / periodicity * t) ** 2) ** -.25
            up_prop *= .5 * np.cos(periodicity * t)
            up_prop += .5
            return up_prop


        popt, pcov = scipy.optimize.curve_fit(
            t2star_decay_3,
            xdata=delta_t * np.arange(n_time_steps),
            ydata=propabilities,
            p0=np.asarray([sigma_f, sigma_f])
        )


        popt, pcov = scipy.optimize.curve_fit(
            t2star_decay_5,
            xdata=delta_t * np.arange(n_time_steps),
            ydata=propabilities,
            p0=np.asarray([sigma_f, sigma_f, driving_frequency, sigma_f])
        )

        self.assertLess(np.linalg.norm(
            propabilities - t2star_decay(delta_t * np.arange(n_time_steps),
                           sigma_driving=sigma_f)) / len(propabilities), 1e-3)

        """
import numpy as np
import unittest

from qopt.matrix import DenseOperator
from qopt.solver_algorithms import SchroedingerSolver
from qopt.cost_functions import StateInfidelity
from qopt.simulator import Simulator

sigma_x = DenseOperator(np.asarray([[0, 1], [1, 0]]))
sigma_y = DenseOperator(np.asarray([[0, -1j], [1j, 0]]))
sigma_z = DenseOperator(np.asarray([[1, 0], [0, -1]]))

n_time_steps = 5
delta_t = .5 * np.pi

up = DenseOperator(np.asarray([[1], [0]]))
down = DenseOperator(np.asarray([[0], [1]]))

schroedinger_solver = SchroedingerSolver(h_drift=[0 * sigma_x] * n_time_steps,
                                         h_ctrl=[sigma_x, sigma_y],
                                         tau=delta_t * np.ones(n_time_steps),
                                         initial_state=up)


class TestFidelitySchroedingerEq(unittest.TestCase):
    def test_state_fid(self):
        cost_fkt = StateInfidelity(schroedinger_solver, target=down)

        simulator = Simulator(solvers=[
            schroedinger_solver,
        ],
Example #6
0
    'leakage': 1.8e-5,
    'entanglement_bound': 1e-10,
    'fast_white': 1.6e-3,
    'quasi_static_elec': 4.9e-4,
    'quasi_static_magn': 1.7e-4
}

REQUIRED_ACCURACY = {
    'leakage': .1,
    'fast_white_mc': .15,
    'fast_white_me': .31,
    'quasi_static_elec': .1,
    'quasi_static_magn': .1
}

SIGMA_X = DenseOperator(qutip.sigmax())
SIGMA_Y = DenseOperator(qutip.sigmay())
SIGMA_Z = DenseOperator(qutip.sigmaz())
SIGMA_0 = DenseOperator(np.eye(2))

# global constants (Table 1 in the paper)
SIGMA_EPS = 8e-3  # mV
SIGMA_b = .3  # mT
EPSILON_0 = .272  # mV
J_0 = 1  # ns^-1
EPSILON_MIN = -5.4 * EPSILON_0  # mV
EPSILON_MAX = 2.4 * EPSILON_0  # mV
F_S = 1  # GS/s
B_G = 500  # mT

# changing dimensions: 1mT ~ 5.6 MHz ~ 5.6 / mu s ~ 0.0056 / ns
Example #7
0
    def test_relative_gradients_xy(self):
        amp_bound = rabi.rabi_frequency_max / rabi.lin_freq_rel
        np.random.seed(0)
        initial_pulse = amp_bound * (
            2 * np.random.rand(rabi.n_time_samples, 2) - 1)

        ntg_quasi_static = NTGQuasiStatic(
            standard_deviation=[
                rabi.sigma_rabi,
            ],
            n_samples_per_trace=rabi.n_time_samples * rabi.oversampling,
            n_traces=10,
            always_redraw_samples=False,
            sampling_mode='uncorrelated_deterministic')

        tslot = SchroedingerSMonteCarlo(
            h_drift=[
                0 * rabi.h_drift,
            ],
            h_ctrl=rabi.h_ctrl,
            h_noise=[
                rabi.h_drift,
            ],
            noise_trace_generator=ntg_quasi_static,
            initial_state=DenseOperator(np.eye(2)),
            tau=[
                rabi.time_step,
            ] * rabi.n_time_samples,
            is_skew_hermitian=True,
            exponential_method='Frechet',
            transfer_function=rabi.exponential_transfer_function,
            amplitude_function=rabi.lin_amp_func)

        entanglement_infid = OperationInfidelity(
            solver=tslot,
            target=rabi.x_half,
            fidelity_measure='entanglement',
            index=['Entanglement Fidelity QS-Noise XY-Control'])

        tslot_noise = SchroedingerSMonteCarlo(
            h_drift=[
                0 * rabi.h_drift,
            ],
            h_ctrl=rabi.h_ctrl,
            h_noise=[
                rabi.h_drift,
            ],
            noise_trace_generator=ntg_quasi_static,
            initial_state=DenseOperator(np.eye(2)),
            tau=[
                rabi.time_step,
            ] * rabi.n_time_samples,
            is_skew_hermitian=True,
            exponential_method='Frechet',
            transfer_function=rabi.exponential_transfer_function,
            amplitude_function=rabi.lin_amp_func)

        entanglement_infid_qs_noise_xy = OperationNoiseInfidelity(
            solver=tslot_noise,
            target=rabi.x_half,
            fidelity_measure='entanglement',
            index=['Entanglement Fidelity QS-Noise XY-Control'],
            neglect_systematic_errors=True)

        dynamics = Simulator(solvers=[
            tslot,
        ],
                             cost_fktns=[
                                 entanglement_infid,
                             ])

        dynamics_noise = Simulator(solvers=[
            tslot_noise,
        ],
                                   cost_fktns=[entanglement_infid_qs_noise_xy])

        _, rel_grad_deviation_unperturbed = \
            dynamics.compare_numeric_to_analytic_gradient(initial_pulse)
        self.assertLess(rel_grad_deviation_unperturbed, 1e-6)

        _, rel_grad_deviation_qs_noise = \
            dynamics_noise.compare_numeric_to_analytic_gradient(initial_pulse)
        self.assertLess(rel_grad_deviation_qs_noise, 1e-4)
Example #8
0
    def test_phase_control_gradient(self):
        amp_bound = rabi.rabi_frequency_max / rabi.lin_freq_rel
        phase_bound_upper = 50 / 180 * np.pi
        phase_bound_lower = -50 / 180 * np.pi

        def random_phase_control_pulse(n):
            amp = amp_bound * (2 * np.random.rand(n) - 1)
            phase = (phase_bound_upper - phase_bound_lower) \
                * np.random.rand(n) \
                - (phase_bound_upper - phase_bound_lower) / 2
            return np.concatenate(
                (np.expand_dims(amp, 1), np.expand_dims(phase, 1)), axis=1)

        dynamics_phase_control = Simulator(
            solvers=[rabi.solver_qs_noise_phase_control],
            cost_fktns=[rabi.entanglement_infid_phase_control])

        ntg_quasi_static = NTGQuasiStatic(
            standard_deviation=[
                rabi.sigma_rabi,
            ],
            n_samples_per_trace=rabi.n_time_samples * rabi.oversampling,
            n_traces=10,
            always_redraw_samples=False,
            sampling_mode='uncorrelated_deterministic')

        time_slot_comp_qs_noise_phase_control = SchroedingerSMonteCarlo(
            h_drift=[
                0 * rabi.h_drift,
            ],
            h_ctrl=rabi.h_ctrl,
            h_noise=[
                rabi.h_drift,
            ],
            noise_trace_generator=ntg_quasi_static,
            initial_state=DenseOperator(np.eye(2)),
            tau=[
                rabi.time_step,
            ] * rabi.n_time_samples,
            is_skew_hermitian=True,
            exponential_method='Frechet',
            transfer_function=rabi.identity_transfer_function,
            amplitude_function=rabi.phase_ctrl_amp_func)

        entanglement_infid_qs_noise_phase_control = OperationNoiseInfidelity(
            solver=time_slot_comp_qs_noise_phase_control,
            target=rabi.x_half,
            fidelity_measure='entanglement',
            index=['Entanglement Fidelity QS-Noise Phase Control'],
            neglect_systematic_errors=True)

        dynamics_phase_control_qs_noise = Simulator(
            solvers=[
                time_slot_comp_qs_noise_phase_control,
            ],
            cost_fktns=[
                entanglement_infid_qs_noise_phase_control,
            ])

        np.random.seed(0)
        inital_pulse = random_phase_control_pulse(rabi.n_time_samples)

        _, rel_grad_deviation_unperturbed = dynamics_phase_control.\
            compare_numeric_to_analytic_gradient(inital_pulse)
        self.assertLess(rel_grad_deviation_unperturbed, 2e-6)

        _, rel_grad_deviation_qs_noise = dynamics_phase_control_qs_noise.\
            compare_numeric_to_analytic_gradient(inital_pulse)
        self.assertLess(rel_grad_deviation_qs_noise, 5e-5)
Example #9
0
                                  n_traces=8,
                                  always_redraw_samples=False,
                                  sampling_mode='uncorrelated_deterministic')

# ##################### 7. Time Slot Computer #################################
# The time slot computer calculates the evolution of the qubit taking into
# account the amplitude and transfer function and also the noise traces if
# required.

# 7.1 xy-control
solver_unperturbed_xy = SchroedingerSolver(
    h_drift=[
        0 * h_drift,
    ],
    h_ctrl=h_ctrl,
    initial_state=DenseOperator(np.eye(2)),
    tau=[
        time_step,
    ] * n_time_samples,
    is_skew_hermitian=True,
    exponential_method=exponential_method,
    transfer_function=exponential_transfer_function,
    amplitude_function=lin_amp_func)

solver_qs_noise_xy = SchroedingerSMonteCarlo(
    h_drift=[
        0 * h_drift,
    ],
    h_ctrl=h_ctrl,
    h_noise=[
        h_drift,
Example #10
0
def create_discrete_classes(n_bit_ph: int, n_bit_amp: int):
    n_max_phase = 2**n_bit_ph - 1
    delta_phase = phase_max / n_max_phase * np.pi / 180

    # 2.2: from our group
    amp_bound = rabi_frequency_max * 2 * np.pi / lin_freq_rel

    n_max_amp = 2**n_bit_amp - 1
    delta_amp = amp_bound / n_max_amp

    discrete_tf_phase = LinearTF(oversampling=1,
                                 bound_type=None,
                                 num_ctrls=1,
                                 linear_factor=delta_phase)

    discrete_tf_amp = LinearTF(oversampling=1,
                               bound_type=None,
                               num_ctrls=1,
                               linear_factor=delta_amp)

    discrete_tf = ParallelTF(tf1=discrete_tf_amp, tf2=discrete_tf_phase)

    total_tf = ConcatenateTF(tf1=discrete_tf,
                             tf2=exponential_transfer_function)
    total_tf.set_times(time_step * np.ones(n_time_samples))

    ts_comp_unperturbed_pc_discrete = SchroedingerSolver(
        h_drift=[
            0 * h_drift,
        ] * n_time_samples * oversampling,
        h_ctrl=h_ctrl,
        initial_state=DenseOperator(np.eye(2)),
        tau=[
            time_step / oversampling,
        ] * n_time_samples * oversampling,
        is_skew_hermitian=True,
        exponential_method=exponential_method,
        transfer_function=total_tf,
        amplitude_function=phase_ctrl_amp_func)

    time_slot_comp_qs_noise_pc_discrete = SchroedingerSMonteCarlo(
        h_drift=[
            0 * h_drift,
        ] * n_time_samples * oversampling,
        h_ctrl=h_ctrl,
        h_noise=[
            h_drift,
        ],
        noise_trace_generator=ntg_quasi_static,
        initial_state=DenseOperator(np.eye(2)),
        tau=[
            time_step / oversampling,
        ] * n_time_samples * oversampling,
        is_skew_hermitian=True,
        exponential_method=exponential_method,
        transfer_function=total_tf,
        amplitude_function=phase_ctrl_amp_func)

    qs_noise_pc_discrete = OperationNoiseInfidelity(
        solver=time_slot_comp_qs_noise_pc_discrete,
        target=x_half,
        fidelity_measure='entanglement',
        index=['Entanglement Fidelity QS-Noise Phase Control'],
        neglect_systematic_errors=True)

    entanglement_infid_pc_discrete = OperationInfidelity(
        solver=ts_comp_unperturbed_pc_discrete,
        target=x_half,
        fidelity_measure='entanglement',
        index=['Entanglement Fidelity Phase Control'])

    return [ts_comp_unperturbed_pc_discrete,
            time_slot_comp_qs_noise_pc_discrete], \
           [entanglement_infid_pc_discrete, qs_noise_pc_discrete]
Example #11
0
import numpy as np

from qopt.matrix import DenseOperator
from qopt.energy_spectrum import plot_energy_spectrum

pauli_z = DenseOperator(np.asarray([[1, 0], [0, -1]]))
pauli_x = DenseOperator(np.asarray([[0, 1], [1, 0]]))

tau_z = pauli_z.kron(pauli_z.identity_like())
tau_x = pauli_x.kron(pauli_x.identity_like())
sigma_z = (pauli_z.identity_like()).kron(pauli_z)
sigma_x = (pauli_x.identity_like()).kron(pauli_x)
sigma_x_tau_x = pauli_x.kron(pauli_x)


def example_hamiltonian_flopping(detuning):
    hamiltonian = []
    t_c = 20
    e_z = 24
    g_mu_b_b_x = 15
    g_mu_b_b_z = 4
    for eps in detuning:
        omega = np.sqrt(eps**2 + (2 * t_c)**2)
        theta = np.arctan(eps / (2 * t_c))
        hamiltonian.append(.5 * omega * tau_z + (e_z / 2) * sigma_z -
                           (g_mu_b_b_x / 2) * sigma_x *
                           (np.cos(theta) * tau_x - np.sin(theta) * tau_z) -
                           (g_mu_b_b_z / 2) * sigma_z *
                           (np.cos(theta) * tau_x - np.sin(theta) * tau_z))
    return hamiltonian
    def test_quasi_static_noise(self):

        expected_t2star = np.sqrt(2 / variance_f)

        ntg = NTGQuasiStatic(standard_deviation=[
            sigma_f,
        ],
                             n_samples_per_trace=n_time_steps,
                             n_traces=n_noise_traces,
                             always_redraw_samples=False,
                             sampling_mode='uncorrelated_deterministic')

        tslot_comp = SchroedingerSMonteCarlo(h_drift=[
            h_drift,
        ] * n_time_steps,
                                             h_ctrl=[
                                                 .5 * sigma_z,
                                             ],
                                             h_noise=[.5 * sigma_z],
                                             initial_state=DenseOperator(
                                                 np.eye(2)),
                                             tau=[
                                                 delta_t,
                                             ] * n_time_steps,
                                             noise_trace_generator=ntg,
                                             exponential_method='Frechet')

        def up_amplitude(unitary):
            probability = projector_left @ unitary.data @ projector_right
            return np.abs(probability)**2

        tslot_comp.set_optimization_parameters(
            (2 * np.pi * delta_rabi) * np.ones((n_time_steps, 1)))
        forward_propagators = tslot_comp.forward_propagators_noise

        propabilities = np.zeros((n_noise_traces, n_time_steps))
        for i in range(n_noise_traces):
            for j in range(n_time_steps):
                propabilities[i, j] = up_amplitude(forward_propagators[i][j])

        propabilities = np.mean(propabilities, axis=0)

        # plt.figure()
        # plt.plot(delta_t * np.arange(n_time_steps), propabilities, marker='.')

        def t2star_decay(t, delta_f, t2_star):
            return .5 * np.exp(-(t / t2_star)**2) * np.cos(
                2 * np.pi * delta_f * t) + .5

        popt, pcov = scipy.optimize.curve_fit(
            t2star_decay,
            xdata=delta_t * np.arange(n_time_steps),
            ydata=propabilities,
            p0=np.asarray([delta_rabi, expected_t2star]))

        self.assertLess(
            np.linalg.norm(propabilities - t2star_decay(
                delta_t * np.arange(n_time_steps), popt[0], popt[1])) /
            len(propabilities), 1e-3)

        self.assertLess(
            np.abs((expected_t2star - popt[1]) / (expected_t2star + popt[1])),
            1e-2)
        """
    def test_fast_noise(self):
        def prefactor_function(transferred_parameters):
            return variance_lindbladt * np.ones_like(transferred_parameters)

        expected_t2_lindbladt = 2 / variance_lindbladt

        lindbladt_operators = [
            .5 * DenseOperator(np.asarray([[0, 1], [1, 0]])),
        ]

        tslot_comp_lindblad = LindbladSolver(
            h_drift=[
                h_drift,
            ] * n_time_steps,
            h_ctrl=[
                .5 * sigma_z,
            ],
            initial_state=DenseOperator(np.eye(4)),
            tau=[
                delta_t,
            ] * n_time_steps,
            exponential_method='Frechet',
            lindblad_operators=lindbladt_operators,
            prefactor_function=prefactor_function)

        tslot_comp_lindblad.set_optimization_parameters(
            (2 * np.pi * delta_rabi) * np.ones((n_time_steps, 1)))

        forward_propagators_lindbladt = tslot_comp_lindblad.forward_propagators

        def vec_to_density_matrix(vec: np.ndarray):
            return vec @ vec.conj().transfer_matrix

        def linearize_matrix(matrix: np.ndarray):
            return matrix.T.flatten()

        def vector_to_matrix(vec: np.ndarray):
            return vec.reshape((2, 2)).transfer_matrix

        initial = linearize_matrix(vec_to_density_matrix(x_half @ up))
        probabilities_lindbladt = np.zeros(len(forward_propagators_lindbladt))
        probabilities_lindbladt_c = np.zeros(
            len(forward_propagators_lindbladt), dtype=complex)

        sigma_x = np.asarray([[0, 1], [1, 0]])

        for i, prop in enumerate(forward_propagators_lindbladt):
            density = prop.data @ initial
            density = vector_to_matrix(density)
            probabilities_lindbladt[i] = np.trace(density @ sigma_x)
            probabilities_lindbladt_c[i] = np.trace(density @ sigma_x)

        def t2_time(t, t2):
            return -1 * np.sin(2 * np.pi * t * delta_rabi) \
                   * np.exp(-.5 * t / t2)

        popt, pcov = scipy.optimize.curve_fit(
            t2_time,
            xdata=delta_t * np.arange(n_time_steps + 1),
            ydata=probabilities_lindbladt,
            p0=np.asarray([expected_t2_lindbladt]))

        self.assertLess(
            np.linalg.norm(probabilities_lindbladt - t2_time(
                delta_t * np.arange(n_time_steps + 1), t2=popt[0])) /
            len(probabilities_lindbladt), 1e-6)

        self.assertLess(
            np.abs((expected_t2_lindbladt - popt[0]) /
                   (expected_t2_lindbladt + popt[0])), 1e-6)
        """
from qopt.matrix import DenseOperator
from qopt.noise import NTGQuasiStatic
from qopt.solver_algorithms import SchroedingerSMonteCarlo, LindbladSolver

import qopt.examples.rabi_driving.setup as rabi
import numpy as np
import scipy.optimize

from unittest import TestCase

sigma_z = DenseOperator(np.asarray([[1, 0], [0, -1]]))
h_drift = DenseOperator(np.zeros((2, 2)))

n_time_steps = 120
n_noise_traces = 200  # int(10 * 60 * 1e6 / 35)
evolution_time = 35e-6

delta_t = evolution_time / n_time_steps
delta_rabi = 1.5 / 10 * 1e6

# Tom
# todo: he seems to assume angular frequencies in his spectrum
S_01 = 3e8
S_02 = 3e4
# S(f) = S_01 / f + S_02 / f^2

f_min = 1 / 10 / 60  # 1 over 10 minutes
f_max = 1 / 35e-6

variance_f = S_01 * (np.log(f_max) - np.log(f_min)) \
             - S_02 * (1 / f_max - 1 / f_min)