<commit_before>import abc
import random
import math
import logging
import proso.django.log
from collections import defaultdict


LOGGER = logging.getLogger('django.request')


class ItemSelection:

    __metaclass__ = abc.ABCMeta

    def __init__(self, predictive_model, target_probability=0.7):
        self._predictive_model = predictive_model
        self._target_probability = target_probability
        self._predictions_cache = None
        self._rolling_success = None

    @abc.abstractmethod
    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        """
        Returns a list of items chosen to practice and a list of JSONs (or
        Nones) providing meta info about the selection.
        """
        pass

    def get_predictions(self, environment, user=None, items=None, time=None):
        if self._predictions_cache is None:
            if user is None:
                raise Exception('Can not compute predictions without user.')
            if items is None:
                raise Exception('Can not compute predictions without items.')
            if time is None:
                raise Exception('Can not compute predictions without time.')
            self._predictions_cache = dict(zip(items, self._predictive_model.predict_more_items(environment, user, items, time)))
        return self._predictions_cache

    def get_target_probability(self):
        return self._target_probability

    def get_rolling_success(self, environment, user, practice_context=None):
        if self._rolling_success is None:
            self._rolling_success = environment.rolling_success(user=user, context=practice_context)
        return self._rolling_success


class RandomItemSelection(ItemSelection):

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        candidates = random.sample(items, min(n, len(items)))
        # HACK: option selector needs predictions already prepared
        self.get_predictions(environment, user, items, time)
        return candidates, [None for _ in candidates]

    def __str__(self):
        return 'RANDOM ITEM SELECTION'


class TestWrapperItemSelection(ItemSelection):

    def __init__(self, item_selector, nth=10):
        self._item_selector = item_selector
        self._nth = nth

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        if self._nth < n:
            raise Exception('Number of items ({}) to select has to be lower than or equal to the "nth" ({}) parameter.'.format(n, self._nth))
        items_in_queue = kwargs.get('items_in_queue', 0)
        number_of_answers = environment.number_of_answers(user=user, context=practice_context) + items_in_queue
        test_position = number_of_answers % self._nth
        if test_position != 0:
            test_position = self._nth - test_position
        if test_position >= n:
            return self._item_selector.select(environment, user, items, time, practice_context, n, **kwargs)
        LOGGER.debug('Providing random test item on position {}, items in queue {}'.format(test_position, items_in_queue))
        # HACK: option selector needs predictions already prepared
        self.get_predictions(environment, user, items, time)
        test_item = random.choice(items)
        test_meta = {'test': 'random_without_options'}
        items = filter(lambda i: i != test_item, items)
        selected_items, meta = self._item_selector.select(environment, user, items, time, practice_context, n - 1, **kwargs) if n - 1 > 0 else ([], [])
        return selected_items[:test_position] + [test_item] + selected_items[test_position:], meta[:test_position] + [test_meta] + meta[test_position:]

    def get_predictions(self, environment, user=None, items=None, time=None):
        return self._item_selector.get_predictions(environment, user=user, items=items, time=time)

    def get_target_probability(self):
        return self._item_selector.get_target_probability()

    def get_rolling_success(self, environment, user, practice_context=None):
        return self._item_selector.get_rolling_success(environment, user, practice_context=practice_context)


class ScoreItemSelection(ItemSelection):

    def __init__(
            self, predictive_model, weight_probability=10.0, weight_number_of_answers=5.0,
            weight_time_ago=120, weight_parent_time_ago=120, weight_parent_number_of_answers=2.5,
            target_probability=0.8, recompute_parent_score=True):
        ItemSelection.__init__(self, predictive_model, target_probability)
        self._weight_probability = weight_probability
        self._weight_number_of_answers = weight_number_of_answers
        self._weight_time_ago = weight_time_ago
        self._target_probability = target_probability
        self._weight_parent_time_ago = weight_parent_time_ago
        self._weight_parent_number_of_answers = weight_parent_number_of_answers
        self._recompute_parent_score = recompute_parent_score

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        answers_num = dict(zip(items, environment.number_of_answers_more_items(user=user, items=items)))
        last_answer_time = dict(zip(items, environment.last_answer_time_more_items(user=user, items=items)))
        probability = self.get_predictions(environment, user, items, time)
        parents = dict(zip(items, environment.get_items_with_values_more_items('parent', items=items)))
        # The current implementation of retrieving features for the parent
        # items provides only an under-approximation of the real state.
        last_answer_time_parents = self._last_answer_time_for_parents(environment, parents, last_answer_time)
        answers_num_parents = self._answers_num_for_parents(environment, parents, answers_num)
        prob_target = adjust_target_probability(self._target_probability, self.get_rolling_success(environment, user, practice_context))

        if proso.django.log.is_active():
            for item in items:
                if len(parents.get(item, [])) == 0:
                    LOGGER.warn("The item %s has no parent" % item)

        def _score(item):<commit_msg>be able to turn off adjustment of difficulty based on user's history<commit_after>import abc
import random
import math
import logging
import proso.django.log
from collections import defaultdict


LOGGER = logging.getLogger('django.request')


class ItemSelection:

    __metaclass__ = abc.ABCMeta

    def __init__(self, predictive_model, target_probability=0.7):
        self._predictive_model = predictive_model
        self._target_probability = target_probability
        self._predictions_cache = None
        self._rolling_success = None

    @abc.abstractmethod
    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        """
        Returns a list of items chosen to practice and a list of JSONs (or
        Nones) providing meta info about the selection.
        """
        pass

    def get_predictions(self, environment, user=None, items=None, time=None):
        if self._predictions_cache is None:
            if user is None:
                raise Exception('Can not compute predictions without user.')
            if items is None:
                raise Exception('Can not compute predictions without items.')
            if time is None:
                raise Exception('Can not compute predictions without time.')
            self._predictions_cache = dict(zip(items, self._predictive_model.predict_more_items(environment, user, items, time)))
        return self._predictions_cache

    def get_target_probability(self):
        return self._target_probability

    def get_rolling_success(self, environment, user, practice_context=None):
        if self._rolling_success is None:
            self._rolling_success = environment.rolling_success(user=user, context=practice_context)
        return self._rolling_success


class RandomItemSelection(ItemSelection):

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        candidates = random.sample(items, min(n, len(items)))
        # HACK: option selector needs predictions already prepared
        self.get_predictions(environment, user, items, time)
        return candidates, [None for _ in candidates]

    def __str__(self):
        return 'RANDOM ITEM SELECTION'


class TestWrapperItemSelection(ItemSelection):

    def __init__(self, item_selector, nth=10):
        self._item_selector = item_selector
        self._nth = nth

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        if self._nth < n:
            raise Exception('Number of items ({}) to select has to be lower than or equal to the "nth" ({}) parameter.'.format(n, self._nth))
        items_in_queue = kwargs.get('items_in_queue', 0)
        number_of_answers = environment.number_of_answers(user=user, context=practice_context) + items_in_queue
        test_position = number_of_answers % self._nth
        if test_position != 0:
            test_position = self._nth - test_position
        if test_position >= n:
            return self._item_selector.select(environment, user, items, time, practice_context, n, **kwargs)
        LOGGER.debug('Providing random test item on position {}, items in queue {}'.format(test_position, items_in_queue))
        # HACK: option selector needs predictions already prepared
        self.get_predictions(environment, user, items, time)
        test_item = random.choice(items)
        test_meta = {'test': 'random_without_options'}
        items = filter(lambda i: i != test_item, items)
        selected_items, meta = self._item_selector.select(environment, user, items, time, practice_context, n - 1, **kwargs) if n - 1 > 0 else ([], [])
        return selected_items[:test_position] + [test_item] + selected_items[test_position:], meta[:test_position] + [test_meta] + meta[test_position:]

    def get_predictions(self, environment, user=None, items=None, time=None):
        return self._item_selector.get_predictions(environment, user=user, items=items, time=time)

    def get_target_probability(self):
        return self._item_selector.get_target_probability()

    def get_rolling_success(self, environment, user, practice_context=None):
        return self._item_selector.get_rolling_success(environment, user, practice_context=practice_context)


class ScoreItemSelection(ItemSelection):

    def __init__(
            self, predictive_model, weight_probability=10.0, weight_number_of_answers=5.0,
            weight_time_ago=120, weight_parent_time_ago=120, weight_parent_number_of_answers=2.5,
            target_probability=0.8, recompute_parent_score=True, history_adjustment=True):
        ItemSelection.__init__(self, predictive_model, target_probability)
        self._weight_probability = weight_probability
        self._weight_number_of_answers = weight_number_of_answers
        self._weight_time_ago = weight_time_ago
        self._target_probability = target_probability
        self._weight_parent_time_ago = weight_parent_time_ago
        self._weight_parent_number_of_answers = weight_parent_number_of_answers
        self._recompute_parent_score = recompute_parent_score

    def select(self, environment, user, items, time, practice_context, n, **kwargs):
        answers_num = dict(zip(items, environment.number_of_answers_more_items(user=user, items=items)))
        last_answer_time = dict(zip(items, environment.last_answer_time_more_items(user=user, items=items)))
        probability = self.get_predictions(environment, user, items, time)
        parents = dict(zip(items, environment.get_items_with_values_more_items('parent', items=items)))
        # The current implementation of retrieving features for the parent
        # items provides only an under-approximation of the real state.
        last_answer_time_parents = self._last_answer_time_for_parents(environment, parents, last_answer_time)
        answers_num_parents = self._answers_num_for_parents(environment, parents, answers_num)
        if history_adjustment:
            prob_target = adjust_target_probability(self._target_probability, self.get_rolling_success(environment, user, practice_context))
        else:
            prob_target = self._target_probability

        if proso.django.log.is_active():
            for item in items:
                if len(parents.get(item, [])) == 0:
                    LOGGER.warn("The item %s has no parent" % item)

        def _score(item):
{'fraction_non_alphanumeric': 0.08471205854279351, 'fraction_numerical': 0.003977091950365892, 'mean_word_length': 3.6054945054945056, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '3492800', 'n_tokens_mistral': 3546, 'n_tokens_neox': 3439, 'n_words': 860}