示例#1
0
    def test_all_noise_conditions_see_noise(self):
        """Test that all the noise conditions actually do see noise in the first
        3 actions"""
        action_number_check_threshold = 3

        # Make sure we're running the same condition that we will have for the
        # study. This is where we went wrong last time
        self.sm.max_dx_suggestions = 3
        self.sm.max_ax_suggestions = 3
        self.sm.pad_suggestions = True
        self.sm.save()

        # Iterate through the study conditions
        for study_condition in [
            User.StudyConditions.DX_90, User.StudyConditions.AX_90, User.StudyConditions.DXAX_90,
            User.StudyConditions.DX_80, User.StudyConditions.AX_90, User.StudyConditions.DXAX_80,
        ]:
            self.user.study_condition = study_condition
            self.user.save()

            # Then run the same rigamarole of going testing noise without
            # padding
            for start_state_str, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
                encountered_noise = False
                self.user.number_state_requests = -1
                self.user.save()

                # There has to be some noise before the end of the optimal
                # action sequence
                for idx, (action, expected_values) in enumerate(action_sequence[:-1]):
                    self.user.number_state_requests += 1
                    self.user.save()

                    self._reset_rng(idx)

                    state = State(expected_values['server_state_tuple'])

                    # If DX should be shown, then calculate the noise probabilty
                    if self.user.show_dx_suggestions:
                        expected_suggestions = expected_values['dx_suggestions']
                        suggestions, _, will_corrupt = self._test_dx_suggestions(state, action, expected_suggestions, pad=True)
                        encountered_noise = encountered_noise or (will_corrupt and idx < action_number_check_threshold)

                    # If we should show action suggestions, then check for noise
                    if self.user.show_ax_suggestions:
                        expected_suggestions = [] if idx == len(action_sequence)-1 else [action_sequence[idx+1][0]]
                        suggestions, _, will_corrupt = self._test_ax_suggestions(state, action, expected_suggestions, pad=True)
                        encountered_noise = encountered_noise or (will_corrupt and idx < action_number_check_threshold)

                    # Check the rng state
                    self.user.refresh_from_db()
                    self.assertEqual(Suggestions.get_next_rng_seed(self.rng), self.user.rng_state)

                # Check that we have encountered noise in this condition
                self.assertTrue(encountered_noise, f"Did not encounter noise in {study_condition}, {start_state_str}")
示例#2
0
    def test_optimal_action(self):
        """Test the optimal actions method from the Suggestions"""
        for start_state_str, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                state = State(expected_values['server_state_tuple'])
                expected_suggestions = [] if idx == len(action_sequence)-1 else [action_sequence[idx+1][0]]

                # Get the suggestions
                suggestions = self.suggestions_provider.optimal_action(state, action)

                # Test the suggestions
                self.assertListEqual(expected_suggestions, suggestions)
示例#3
0
    def test_ordered_diagnoses(self):
        """Test the ordered diagnosis method from the Suggestions"""
        for start_state_str, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                state = State(expected_values['server_state_tuple'])
                expected_suggestions = expected_values['dx_suggestions']

                # Get the suggestions & test them
                suggestions = self.suggestions_provider.ordered_diagnoses(state, action, accumulate=True)
                self.assertListEqual(expected_suggestions, suggestions)

                suggestions = self.suggestions_provider.ordered_diagnoses(state, action)
                self.assertListEqual([expected_suggestions[0]], suggestions)
示例#4
0
    def test_noisy_dx_suggestions_no_padding(self):
        """Test the addition of noise to the DX suggestions, without adding
        padding"""
        self.user.study_condition = User.StudyConditions.DXAX_70
        self.user.save()
        self.assertEqual(0.3, self.user.noise_level)

        for start_state_str, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                self.user.number_state_requests += 1
                self.user.save()

                self._reset_rng(idx)
                state = State(expected_values['server_state_tuple'])
                expected_suggestions = expected_values['dx_suggestions']

                self._test_dx_suggestions(state, action, expected_suggestions, pad=False)

                # Check the rng state
                self.user.refresh_from_db()
                self.assertEqual(Suggestions.get_next_rng_seed(self.rng), self.user.rng_state)
示例#5
0
    def test_multiple_suggestions_without_padding(self):
        """Test the return of multiple suggestions without padding to ensure a
        constant number of suggestions at all timesteps"""
        self.sm.max_dx_suggestions = 2
        self.sm.max_ax_suggestions = 3
        self.sm.save()
        self.user.refresh_from_db()

        # Refresh the values in the suggestions provider
        self.suggestions_provider = Suggestions(self.user)

        for start_state, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                state = State(expected_values['server_state_tuple'])

                expected_suggestions = expected_values['dx_suggestions']
                _, _, will_corrupt = self._test_dx_suggestions(state, action, expected_suggestions, pad=False)
                self.assertFalse(will_corrupt)

                expected_suggestions = [] if idx == len(action_sequence)-1 else [action_sequence[idx+1][0]]
                _, _, will_corrupt = self._test_ax_suggestions(state, action, expected_suggestions, pad=False)
                self.assertFalse(will_corrupt)
示例#6
0
    def test_multiple_with_noise_and_padding(self):
        """Test multiple suggestions with padding and noise"""
        self.sm.max_dx_suggestions = 3
        self.sm.max_ax_suggestions = 4
        self.sm.pad_suggestions = True
        self.sm.save()

        self.user.study_condition = User.StudyConditions.DXAX_70
        self.user.save()
        self.user.refresh_from_db()
        self.assertEqual(0.3, self.user.noise_level)

        for start_state_str, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                self.user.number_state_requests += 1
                self.user.save()

                self._reset_rng(idx)
                state = State(expected_values['server_state_tuple'])

                # First we do the DX
                expected_suggestions = expected_values['dx_suggestions']

                self._test_dx_suggestions(state, action, expected_suggestions, pad=True)

                # Check the rng state
                self.user.refresh_from_db()
                self.assertEqual(Suggestions.get_next_rng_seed(self.rng), self.user.rng_state)

                # Then we do the AX
                expected_suggestions = [] if idx == len(action_sequence)-1 else [action_sequence[idx+1][0]]

                self._test_ax_suggestions(state, action, expected_suggestions, pad=True)

                # Check the rng state
                self.user.refresh_from_db()
                self.assertEqual(Suggestions.get_next_rng_seed(self.rng), self.user.rng_state)
示例#7
0
    def test_multiple_suggestions_with_padding(self):
        """Test multiple suggestions with padding, but no noise"""
        self.sm.max_dx_suggestions = 3
        self.sm.max_ax_suggestions = 3
        self.sm.pad_suggestions = True
        self.sm.save()
        self.user.refresh_from_db()

        # Refresh the values in the suggestions provider
        self.suggestions_provider = Suggestions(self.user)

        for start_state, action_sequence in constants.OPTIMAL_ACTION_SEQUENCES.items():
            for idx, (action, expected_values) in enumerate(action_sequence):
                state = State(expected_values['server_state_tuple'])

                expected_suggestions = expected_values['dx_suggestions']
                suggestions, _, will_corrupt = self._test_dx_suggestions(state, action, expected_suggestions, pad=True)
                self.assertFalse(will_corrupt)
                self.assertEqual(self.sm.max_dx_suggestions, len(suggestions))

                expected_suggestions = [] if idx == len(action_sequence)-1 else [action_sequence[idx+1][0]]
                suggestions, _, will_corrupt = self._test_ax_suggestions(state, action, expected_suggestions, pad=True)
                self.assertFalse(will_corrupt)
                self.assertEqual(self.sm.max_ax_suggestions, len(suggestions))
示例#8
0
    def _simulate_user(self, user):
        """Simulate the user's experience"""
        actions = user.studyaction_set.order_by('start_timestamp')

        # Get the simulated user and reset them
        sim_user = User.objects.get(username='******')
        sim_user.study_condition = user.study_condition
        sim_user.start_condition = user.start_condition
        sim_user.rng_state = Suggestions.DEFAULT_RNG_SEED
        sim_user.number_state_requests = -1
        sim_user.save()

        # For each state visited by the user, simulate the suggestions
        prev_action = None
        start_state = State(user.start_condition.split('.'))
        schk = Suggestions()  # Just a means to get the optimal alternatives
        for action in actions:
            next_state = State(eval(action.start_state))

            # Get the next state and verify it
            if sim_user.study_condition in Command.V1_NOISE_USAGE_CONDITIONS:
                # Send an empty user, then update the json with the simulated
                # suggestions from the old way of doing things
                json = get_next_state_json(start_state.tuple, prev_action, None)
                json.update(self._v1_noise_get_suggestions_json(next_state, sim_user))
            else:
                json = get_next_state_json(start_state.tuple, prev_action, sim_user)

            assert tuple(json['server_state_tuple']) == next_state.tuple, \
                f"({start_state.tuple}, {prev_action}): {json['server_state_tuple']} != {next_state.tuple}"

            # Add the suggestions
            if user.show_dx_suggestions:
                action.dx_suggestions = json['dx_suggestions']

            if user.show_ax_suggestions:
                action.ax_suggestions = json['ax_suggestions']

            # Add a boolean if the data was corrupted
            if user.noise_level > 0:
                if (
                    user.show_dx_suggestions and
                    schk.ordered_diagnoses(start_state, prev_action)[0] not in action.dx_suggestions
                ):
                    action.corrupted_dx_suggestions = True

                if (
                    user.show_ax_suggestions and
                    schk.optimal_action(start_state, prev_action)[0] not in action.ax_suggestions
                ):
                    action.corrupted_ax_suggestions = True

            # Save the action
            action.save()
            prev_action = action.action
            start_state = State(eval(action.next_state))

        # Simulate the last suggestions call
        if sim_user.study_condition in Command.V1_NOISE_USAGE_CONDITIONS:
            json = get_next_state_json(start_state.tuple, prev_action, None)
            json.update(self._v1_noise_get_suggestions_json(start_state, sim_user))
        else:
            json = get_next_state_json(start_state.tuple, prev_action, sim_user)

        # Check the RNG state
        try:
            assert sim_user.rng_state == user.rng_state, \
                f"Mismatch end state... FML: {user}... {user.rng_state} != {sim_user.rng_state}"
        except Exception as e:
            self.stdout.write(self.style.ERROR(f"{e}"))