예제 #1
0
 def __init__(self, free_sections_only=True, problem=None, constraint=None):
     self.p = Problem()
     if problem is not None:
         self.p = problem
     self.free_sections_only = free_sections_only
     self.section_constraint = constraint or section_constraint
     self.clear_excluded_times()
예제 #2
0
    def solve(self, restrictions):
        """
        Calculates all possible timetable calculations for the given modules
        and the given restrictions.
        """
        if not self.initialized:
            self._initialize()

        problem = Problem()
        for key, module_lessons in self.lectures.items():
            module_lessons = sorted(module_lessons, key=lambda l: l['abbrev'])
            sub_lectures = groupby(module_lessons, lambda l: l['abbrev'])
            for abbrev, lessons in sub_lectures:
                lessons = sorted(lessons, key=lambda l: l['class'])
                combinations = []
                for classnr, cls_lessons in groupby(lessons, lambda l: l['class']):
                    cls_lessons = sorted(cls_lessons, key=lambda l: l['type'])

                    temporary_combinations = []

                    grouped_by_type = [list(v) for k, v in groupby(cls_lessons, lambda l: l['type'])]
                    if len(grouped_by_type) == 1:
                        for g in grouped_by_type:
                            combinations.append(g)
                        continue
                    for lessons_by_type in grouped_by_type:
                        lessons_by_type = sorted(lessons_by_type, key=lambda l: l['team'])
                        u_or_v = []
                        for _, lessons_by_team in groupby(lessons_by_type, lambda l: l['team']):
                            u_or_v.append([l for l in lessons_by_team])

                        if len(temporary_combinations) == 0:
                            temporary_combinations = [u_or_v]
                        else:
                            for combi in temporary_combinations:
                                for x in combi:
                                    for y in u_or_v:
                                        combinations.append(x+y)

                problem.add_variable(abbrev, combinations)

        problem.add_constraint(self._unique_timing, problem._variables.keys())
        for restriction in restrictions:
            if restriction.is_constraint:
                problem.add_constraint(restriction.constraint, problem._variables.keys())

        start = datetime.now()
        solutions = problem.get_solutions()
        print("Calculation took %s seconds" % (datetime.now() - start).total_seconds())
        print("Found %s solutions!" % len(solutions))
        return solutions
예제 #3
0
 def setUp(self):
     self.p = Problem(BacktrackingSolver())
     self.p.add_variable('x', range(3))
     self.p.add_variable('y', range(3))
예제 #4
0
class PointConstaintIntegrationTestForBacktracker(unittest.TestCase):
    def setUp(self):
        self.p = Problem(BacktrackingSolver())
        self.p.add_variable('x', range(3))
        self.p.add_variable('y', range(3))

    def result(self, *iter):
        return tuple(dict(x=x, y=y) for x, y in iter)

    def test_reset_problem(self):
        result1 = self.p.get_solutions()
        self.p.reset()
        self.p.add_variable('x', range(3))
        self.p.add_variable('y', range(3))
        result2 = self.p.get_solutions()
        self.assertEqual(result1, result2)

    def test_save_and_restore_iteration_position(self):
        it = self.p.iter_solutions()
        next(it)
        ref = self.p.save_point()
        second_answer = next(it)
        self.p.reset()
        self.p.add_variable('x', range(3))
        self.p.add_variable('y', range(3))
        self.p.restore_point(ref)
        answer = next(self.p.iter_solutions())
        self.assertEqual(second_answer, answer)

    def test_with_no_constraints_should_have_all_permutations(self):
        # self.p.add_constraint(lambda x, y: x != y, ['x', 'y'])
        expected = self.result((0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2))
        assertEqualContents(self.p.get_solutions(), expected)

    def test_should_have_non_equal_permutations(self):
        expected = self.result((0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1))
        self.p.add_constraint(lambda x, y: x != y, ['x', 'y'])
        assertEqualContents(self.p.get_solutions(), expected)

    def test_should_have_non_equal_permutations_or_sum_to_3(self):
        expected = self.result((0, 1), (0, 2), (1, 0), (2, 0))
        self.p.add_constraint(lambda x, y: x != y, ['x', 'y'])
        self.p.add_constraint(lambda x, y: x + y != 3, ['x', 'y'], [0, 0])
        assertEqualContents(self.p.get_solutions(), expected)

    def test_should_have_non_equal_permutations_while_x_is_lte_1(self):
        expected = self.result((0, 1), (0, 2), (1, 0), (1, 2))
        self.p.add_constraint(lambda x, y: x != y, ['x', 'y'])
        self.p.add_constraint(lambda x: x <= 1, ['x'], [0])
        assertEqualContents(self.p.get_solutions(), expected)
예제 #5
0
 def setUp(self):
     self.p = Problem(BruteForceSolver())
     self.p.add_variable('x', range(3))
     self.p.add_variable('y', range(3))
예제 #6
0
파일: scheduling.py 프로젝트: uyenuong/YACS
 def __init__(self, free_sections_only=True, problem=None):
     self.p = Problem()
     if problem is not None:
         self.p = problem
     self.free_sections_only = free_sections_only
     self.clear_excluded_times()
예제 #7
0
파일: scheduling.py 프로젝트: uyenuong/YACS
class Scheduler(object):
    """High-level API that wraps the course scheduling feature.

    ``free_sections_only``: bool. Determines if the only the available sections should be
                            used when using courses provided. Defaults to True.
    ``problem``: Optional problem instance to provide. If None, the default one is created.

    """
    def __init__(self, free_sections_only=True, problem=None):
        self.p = Problem()
        if problem is not None:
            self.p = problem
        self.free_sections_only = free_sections_only
        self.clear_excluded_times()

    def clear_excluded_times(self):
        """Clears all previously set excluded times."""
        self._excluded_times = []
        return self

    def exclude_time(self, start, end, days):
        """Added an excluded time by start, end times and the days.

        ``start`` and ``end`` are in military integer times (e.g. - 1200 1430).
        ``days`` is a collection of integers or strings of fully-spelt, lowercased days
                 of the week.
        """
        self._excluded_times.append(TimeRange(start, end, days))
        return self

    def exclude_times(self, *tuples):
        """Adds multiple excluded times by tuple of (start, end, days) or by
        TimeRange instance.

        ``start`` and ``end`` are in military integer times (e.g. - 1200 1430).
        ``days`` is a collection of integers or strings of fully-spelt, lowercased days
                 of the week.
        """
        for item in tuples:
            if isinstance(item, TimeRange):
                self._excluded_times.append(item)
            else:
                self.exclude_time(*item)
        return self

    def find_schedules(self, courses=None, generator=False, start=0):
        """Returns all the possible course combinations. Assumes no duplicate courses.

        ``return_generator``: If True, returns a generator instead of collection. Generators
            are friendlier to your memory and save computation time if not all solutions are
            used.
        """
        self.p.reset()
        self.create_variables(courses)
        self.create_constraints(courses)
        self.p.restore_point(start)
        if generator:
            return self.p.iter_solutions()
        return self.p.get_solutions()

    # internal methods -- can be overriden for custom use.
    def get_sections(self, course):
        """Internal use. Returns the sections to use for the solver for a given course.
        """
        return course.available_sections if self.free_sections_only else course.sections

    def time_conflict(self, schedule):
        """Internal use. Determines when the given time range conflicts with the set of
        excluded time ranges.
        """
        for timerange in self._excluded_times:
            if timerange.conflicts_with(schedule):
                return False
        return True

    def create_variables(self, courses):
        """Internal use. Creates all variables in the problem instance for the given
        courses. If given a dict of {course: sections}, will use the provided sections.
        """
        has_sections = isinstance(courses, dict)
        for course in courses:
            self.p.add_variable(course, courses.get(course, []) if has_sections else self.get_sections(course))

    def create_constraints(self, courses):
        """Internal use. Creates all constraints in the problem instance for the given
        courses.
        """
        for i, course1 in enumerate(courses):
            for j, course2 in enumerate(courses):
                if i <= j:
                    continue
                self.p.add_constraint(section_constraint, [course1, course2])
            self.p.add_constraint(self.time_conflict, [course1])