<commit_before>class Observer:
    """Calculates an estimate of the plant state as if the channel
    were noiseless and transmits it to the controller."""
    def __init__(self, sim):
        self.sim = sim
        self.x_u_ideal = DeterministicPlant(sim.params.alpha)
        self.x_u_actual = DeterministicPlant(sim.params.alpha)

    def observe(self, t, y):
        # Update the controlled part of the actual plant
        u_actual_previous = self.sim.globals.u[t-1] if t > 1 else 0
        self.x_u_actual.step(u_actual_previous)

        # Calculate the ideal (noiseless) estimate
        x_est = y # TODO take observation noise into account
        x_est_uncontrolled = x_est - self.x_u_actual.value
        x_est_ideal = x_est_uncontrolled + self.x_u_ideal.value

        # Update the controlled part of the ideal plant
        u_ideal = -self.sim.params.L(t) * x_est_ideal
        self.x_u_ideal.step(u_ideal)

        # Pass to the source and channel encoders
        return (x_est_ideal,)


class Controller:
    def __init__(self, sim):
        self.sim = sim
        self.u_history = []

    def control(self, t, *msg):
        sim = self.sim

        # Decode the state estimate
        assert len(msg) == 2 # One real number, one ??? to indicate mistake
        x_est, mistake = msg

        # Generate the control signal
        u = -sim.params.L(t) * x_est

        # Correct for mistake
        if mistake:
            pass # TODO<commit_msg>Made the noisy Lloyd-Max controller take detected mistakes into account<commit_after>class Observer:
    """Calculates an estimate of the plant state as if the channel
    were noiseless and transmits it to the controller."""
    def __init__(self, sim):
        self.sim = sim
        self.x_u_ideal = DeterministicPlant(sim.params.alpha)
        self.x_u_actual = DeterministicPlant(sim.params.alpha)

    def observe(self, t, y):
        # Update the controlled part of the actual plant
        u_actual_previous = self.sim.globals.u[t-1] if t > 1 else 0
        self.x_u_actual.step(u_actual_previous)

        # Calculate the ideal (noiseless) estimate
        x_est = y # TODO take observation noise into account
        x_est_uncontrolled = x_est - self.x_u_actual.value
        x_est_ideal = x_est_uncontrolled + self.x_u_ideal.value

        # Update the controlled part of the ideal plant
        u_ideal = -self.sim.params.L(t) * x_est_ideal
        self.x_u_ideal.step(u_ideal)

        # Pass to the source and channel encoders
        return (x_est_ideal,)


class Controller:
    def __init__(self, sim):
        self.sim = sim
        self.u_history = []

    def control(self, t, *msg):
        sim = self.sim

        # Decode the state estimate
        # One real number and None or a list to indicate mistake
        assert len(msg) == 2
        x_est, revised_x_est_history = msg

        # Generate the control signal
        u = -sim.params.L(t) * x_est

        # Correct for mistake
        if revised_x_est_history is not None:
            x_correction = DeterministicPlant(sim.params.alpha)
            n_revised_steps = len(revised_x_est_history)

            print("Mistake: n_revised_steps = {}\nrevised_x_est_history = {}"
                    .format(n_revised_steps, revised_x_est_history))

            # First time where there is a difference between estimates
            t1 = t - n_revised_steps

            # Calculate the deviation -x_correction due to the mistake
            for tau in range(t1, t):
                u_actual = self.u_history[tau - 1] # Time starts at 1
                x_corrected = revised_x_est_history[tau - t1]
                u_corrected = -sim.params.L(tau) * x_corrected
                x_correction.step(u_corrected - u_actual)

            u += sim.params.alpha * x_correction.value
{'fraction_non_alphanumeric': 0.07716535433070866, 'fraction_numerical': 0.0034120734908136482, 'mean_word_length': 2.2684391080617496, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '513125', 'n_tokens_mistral': 1222, 'n_tokens_neox': 1134, 'n_words': 335}