Пример #1
0
    def test_london_on_demand_two(self):
        """Test on demand trial data that supposedly had low efficiency"""
        # yapf: disable
        demand = [
            [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 8, 12, 10, 9, 8, 9, 15, 15, 20,
             17, 14, 7, 4],
            [0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 6, 10, 14, 14, 9, 9, 9, 12, 20, 25,
             20, 12, 9, 5],
            [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 7, 12, 15, 12, 10, 9, 12, 12, 16,
             21, 20, 12, 9, 4],
            [0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 7, 10, 13, 13, 9, 9, 11, 15, 17, 24,
             23, 14, 7, 5],
            [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 7, 10, 13, 13, 11, 11, 11, 12, 25,
             29, 29, 20, 12, 9],
            [6, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 12, 19, 18, 17, 16, 16, 18, 24,
             25, 25, 18, 11, 7],
            [4, 0, 0, 0, 0, 0, 0, 0, 3, 6, 7, 12, 19, 19, 17, 16, 16, 18, 23,
             29, 26, 14, 9, 5],
        ]
        # yapf: enable
        min_length = 4
        max_length = 14

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()
        # For these, we really need perfect efficiency
        assert s.efficiency() < 0.01
Пример #2
0
    def _process_task(self, task):
        # 1. Fetch schedule
        self.org = self.client.get_organization(
            task.data.get("organization_id"))
        self.loc = self.org.get_location(task.data.get("location_id"))
        self.role = self.loc.get_role(task.data.get("role_id"))
        self.sched = self.role.get_schedule(task.data.get("schedule_id"))

        self._compute_demand()
        self._subtract_existing_shifts_from_demand()

        # Run the  calculation
        s = Splitter(self.demand,
                     self.sched.data.get("min_shift_length_hour"),
                     self.sched.data.get("max_shift_length_hour"))
        s.calculate()
        s.efficiency()

        # Naive becuase not yet datetimes
        naive_shifts = s.get_shifts()
        logger.info("Starting upload of %s shifts", len(naive_shifts))

        local_start_time = self._get_local_start_time()

        for shift in naive_shifts:
            # We have to think of daylight savings time here, so we need to
            # guarantee that we don't have any errors. We do this by overshooting
            # the timedelta by an extra two hours, then rounding back to midnight.

            logger.debug("Processing shift %s", shift)

            start_day = normalize_to_midnight(
                deepcopy(local_start_time) + timedelta(days=shift["day"]))

            # Beware of time changes - duplicate times are possible
            try:
                start = start_day.replace(hour=shift["start"])
            except pytz.AmbiguousTimeError:
                # Randomly pick one. Minor tech debt.
                start = start_day.replace(hour=shift["start"], is_dst=False)

            stop = start + timedelta(hours=shift["length"])

            # Convert to the strings we are passing up to the cLoUd
            utc_start_str = start.astimezone(self.default_tz).isoformat()
            utc_stop_str = stop.astimezone(self.default_tz).isoformat()

            logger.info("Creating shift with start %s stop %s", start, stop)
            self.role.create_shift(start=utc_start_str, stop=utc_stop_str)
Пример #3
0
    def _process_task(self, task):
        # 1. Fetch schedule
        self.org = self.client.get_organization(
            task.data.get("organization_id"))
        self.loc = self.org.get_location(task.data.get("location_id"))
        self.role = self.loc.get_role(task.data.get("role_id"))
        self.sched = self.role.get_schedule(task.data.get("schedule_id"))

        self._compute_demand()
        self._subtract_existing_shifts_from_demand()

        # Run the  calculation
        s = Splitter(self.demand,
                     self.sched.data.get("min_shift_length_hour"),
                     self.sched.data.get("max_shift_length_hour"))
        s.calculate()
        s.efficiency()

        # Naive becuase not yet datetimes
        naive_shifts = s.get_shifts()
        logger.info("Starting upload of %s shifts", len(naive_shifts))

        local_start_time = self._get_local_start_time()

        for shift in naive_shifts:
            # We have to think of daylight savings time here, so we need to
            # guarantee that we don't have any errors. We do this by overshooting
            # the timedelta by an extra two hours, then rounding back to midnight.

            logger.debug("Processing shift %s", shift)

            start_day = normalize_to_midnight(
                deepcopy(local_start_time) + timedelta(days=shift["day"]))

            # Beware of time changes - duplicate times are possible
            try:
                start = start_day.replace(hour=shift["start"])
            except pytz.AmbiguousTimeError:
                # Randomly pick one. Minor tech debt.
                start = start_day.replace(hour=shift["start"], is_dst=False)

            stop = start + timedelta(hours=shift["length"])

            # Convert to the strings we are passing up to the cLoUd
            utc_start_str = start.astimezone(self.default_tz).isoformat()
            utc_stop_str = stop.astimezone(self.default_tz).isoformat()

            logger.info("Creating shift with start %s stop %s", start, stop)
            self.role.create_shift(start=utc_start_str, stop=utc_stop_str)
Пример #4
0
    def test_online_store_prod_failure(self):
        """This data caused a production error"""
        # yapf: disable
        demand = [
            [8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8],
            [8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8],
            [8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8],
            [8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8],
            [8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8],
        ]
        # yapf: enable
        min_length = 8
        max_length = 8

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()
Пример #5
0
    def test_call_center(self):
        """See if it chokes for call center client data"""
        # yapf: disable
        demand = [
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0],
        ]
        # yapf: enable
        min_length = 9
        max_length = 9

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()
        # For these, we really need perfect efficiency
        assert s.efficiency() < 0.001
Пример #6
0
    def test_la(self):
        """24/7 LA client data"""
        # yapf: disable
        demand = [
            # They sometimes have leading zeros
            [0, 0, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 1],
            [1, 1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3],
            [4, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            [3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3],
            [3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            [4, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            [4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4],
        ]
        # yapf: enable
        min_length = 6
        max_length = 8

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()
        assert s.efficiency() < 0.08
Пример #7
0
    def test_succeeds_with_zero_demand(self):
        # yapf: disable
        demand = [
            [0]*24,
            [0]*24,
            [0]*24,
            [0]*24,
            [0]*24,
            [0]*24,
            [0]*24,
        ]
        # yapf: enable

        min_length = 4
        max_length = 8

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()

        efficiency = s.efficiency()
        assert efficiency == PERFECT_OPTIMALITY
Пример #8
0
    def test_on_demand_old(self):
        """Old on demand data - good test of wrap-around"""
        # yapf: disable
        demand = [
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 4, 4, 6, 6, 7, 7, 5, 2],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 5, 3, 3, 4, 4, 7, 6, 5, 4, 2],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 5, 4, 5, 4, 5, 5, 7, 6, 6, 5, 3],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 5, 5, 2, 5, 6, 7, 6, 6, 5, 3],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 3, 5, 4, 6, 5, 6, 8, 5, 4, 4],
            [3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 6, 5, 2],
            [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 5, 5, 4, 6, 6, 11, 8, 6, 4, 2],
        ]
        # yapf: enable

        min_length = 4
        max_length = 8

        s = Splitter(demand, min_length, max_length)
        s.calculate()
        s.validate()

        efficiency = s.efficiency()
        assert efficiency < EFFICIENCY_LIMIT