Esempio n. 1
0
class ABTesting:

    _algorithms = [ArtsRT(), ArtsRT(0.1, 2, 1.1, 2, 20), ArtsDiffSlow()]

    @classmethod
    def get_algorithm_for_id(cls, id):
        """Returns an algorithm from the_algorithms based on the modulo
        of the ID of the object and the number of algorithms

        :param id: An Integer, for which the algorithm should be returned
        :return: An AlgorithmWrapper containing an ArtsRT object with the parameters
                 specified in WORD_SCHEDULING_ALGORITHM_CONFIG
        """
        idx = cls.__get_algorithm_index_for_id(id)
        return cls._algorithms[idx]

    @classmethod
    def get_algorithm_wrapper_for_id(cls, id):
        algorithm = cls.get_algorithm_for_id(id)
        return AlgorithmWrapper(algorithm)

    @classmethod
    def split_bookmarks_based_on_algorithm(cls, bookmarks):
        groups = []
        for i in range(0, len(cls._algorithms)):
            groups.append([])

        for i in range(0, len(bookmarks)):
            group_idx = cls.__get_algorithm_index_for_id(bookmarks[i].id)
            groups[group_idx].append(bookmarks[i])

        return groups

    @classmethod
    def __get_algorithm_index_for_id(cls, id):
        count_algorithms = len(cls._algorithms)
        return divmod(id, count_algorithms)[1]
Esempio n. 2
0
    def __init__(self, user_id, algorithm=None):
        """
        Create a new algorithm simulation for
        :param user_id: The user id of a user
        :param algorithm: The used word scheduling algorithm (not the wrapper)
        """
        self.user_id = user_id

        self.__create_database()

        if algorithm is None:
            algorithm = ArtsRT()
        self.algo_wrapper = AlgorithmWrapper(algorithm)

        self.bookmarks = self.__get_bookmarks_for_user(self.user_id)
Esempio n. 3
0
class BookmarkPriorityUpdater:
    """

    Handles the related tasks for using word scheduling algorithms
    and also acts as a wrapper that calls the specific algorithm

        update_bookmark_priority

    """

    algorithm_wrapper = AlgorithmWrapper(ArtsRT())

    @classmethod
    @time_this
    def update_bookmark_priority(cls, db, user):
        """ Update all bookmark priorities of one user

        :param db: The connection to the database
        :param user: The user object
        """
        try:
            bookmarks_for_user = user.all_bookmarks_fit_for_study()
            fit_for_study_count = len(bookmarks_for_user)

            zeeguu_core.log(f"{fit_for_study_count} bookmarks fit for study")
            if fit_for_study_count == 0:
                return

            # tuple(0=bookmark, 1=exercise)
            bookmark_exercise_of_user = map(cls._get_exercise_of_bookmark,
                                            bookmarks_for_user)
            b1, b2 = itertools.tee(bookmark_exercise_of_user, 2)

            max_iterations = max(
                pair.exercise.id if pair.exercise is not None else 0
                for pair in b1)
            exercises_and_priorities = [
                cls._calculate_bookmark_priority(x, max_iterations) for x in b2
            ]

            with db.session.no_autoflush:  # might not be needed, but just to be safe
                for each in exercises_and_priorities:
                    entry = BookmarkPriorityARTS.find_or_create(
                        each.bookmark, each.priority)
                    entry.priority = each.priority
                    db.session.add(entry)
                    # print(entry)

            db.session.commit()
        except Exception as e:
            db.session.rollback()
            print('Error during updating bookmark priority')
            print(e)
            print(traceback.format_exc())

    @classmethod
    def _update_exercise_source_stats(cls):
        """Update the ExerciseStats for the ArtsDiffSlow and ArtsDiffFast algorithm to provide
         normalization information between the different exercise sources"""
        exercise_sources = list(ExerciseSource.query.all())
        for source in exercise_sources:
            exercises = Exercise.query.filter_by(source_id=source.id).filter(
                Exercise.solving_speed <= 30000).all()
            reaction_times = list(map(lambda x: x.solving_speed, exercises))
            if len(reaction_times) == 0:
                # magic values for the reaction, if no data exists
                reaction_times = [5000, 6000]
                print('This exercise source has no data yet. ID: ' +
                      str(source.id))

            mean, sd = NormalDistribution.calc_normal_distribution(
                reaction_times)
            if sd is None:
                sd = 1000
            exercise_stats = ExerciseStats.find_or_create(
                db.session, ExerciseStats(source, mean, sd))
            db.session.merge(exercise_stats)

        db.session.commit()

    @classmethod
    def _calculate_bookmark_priority(cls, x, max_iterations):
        """Calculate the (new) priority of a bookmark-exercise pair

        :param x: An instance of the bookmark-exercise information (PriorityInfo)
        :param max_iterations: The current amount of iterations/learning sessions (in the ArtsRT algorithm known as D)
        :return: The bookmark-exercise information (PriorityInfo) with a updated priority
        """
        if x.exercise is not None:

            if x.exercise.solving_speed > 0:
                x.priority = cls.algorithm_wrapper.calculate(
                    x.exercise, max_iterations)

            else:
                # solving speed is -1 for the cases where there was some feedback
                # from the user (either that it's too easy, or that there's something
                # wrong with it. we shouldn't schedule the bookmark in this case.
                # moreover, even if we wanted we can't since there's a log of reaction
                # time somewhere and it won't work with -1!
                x.priority = PriorityInfo.NO_PRIORITY
        else:
            x.priority = PriorityInfo.MAX_PRIORITY
        return x

    @staticmethod
    def _get_exercise_of_bookmark(bookmark):
        if 0 < len(bookmark.exercise_log):
            return PriorityInfo(bookmark=bookmark,
                                exercise=bookmark.exercise_log[-1])

        return PriorityInfo(bookmark=bookmark, exercise=None)
Esempio n. 4
0
                                           words_in_parallel_factor=3,
                                           repetition_correct_factor=0,
                                           repetition_incorrect_factor=0)

    # update exercise source stats
    BookmarkPriorityUpdater._update_exercise_source_stats()

    # optimize for algorithm for these users
    users = User.find_all()

    start = timer()

    user_ids = [user.id for user in users]
    results = []
    for user_id in user_ids:
        algorithm = ArtsRT()
        evaluator = AlgorithmEvaluator(user_id, algorithm, change_limit=1.0)
        variables_to_set = [['d', getattr(algorithm, 'd'), +5],
                            ['b', getattr(algorithm, 'b'), +10],
                            ['w', getattr(algorithm, 'w'), +10]]
        result = evaluator.fit_parameters(variables_to_set, optimization_goals)
        if result is not None:
            count_bookmarks = len(evaluator.fancy.bookmarks)
            count_exercises = sum(
                map(lambda x: len(x.exercise_log), evaluator.fancy.bookmarks))
            result = [
                user_id,
                list(map(lambda x: [x[0], x[1]], result)), count_bookmarks,
                count_exercises
            ]
            results.append(result)