Exemplo n.º 1
0
    def check_shift_16(self, shift, id_shift):
        """
        returns {"exceeds": {(id_shift, id_location): quantity, ... } for
                        operation with quantity above trailer's capacity
                 "too_low": {(id_shift, id_location): quantity, ... } for
                        operation with quantity < min_quantity
                }
        """
        check = SuperDict(exceeds=SuperDict(), too_low=SuperDict())
        for i in range(1, len(shift["route"]) + 1):
            operation = shift["route"][i - 1]
            location = operation["location"]

            if not self.is_customer(location):
                continue

            call_in = self.instance.get_customer_property(location, "callIn")
            if call_in == 0:
                capacity = self.instance.get_customer_property(
                    location, "Capacity")
                min_ope_quantity = self.instance.get_customer(location).get(
                    "MinOperationQuantity", 0)
                if -operation["quantity"] > capacity:
                    check["exceeds"][(id_shift,
                                      location)] = operation["quantity"]
                elif -operation["quantity"] < min_ope_quantity:
                    check["too_low"][(id_shift,
                                      location)] = operation["quantity"]
        check = check.vfilter(lambda v: len(v) != 0)
        return check
Exemplo n.º 2
0
def read_excel(path: str, param_tables_names: list = None) -> dict:
    """
    Read an entire excel file.

    :param path: path of the excel file
    :param param_tables_names: names of the parameter tables
    :return: a dict with a list of dict (records format) for each table.
    """
    is_xl_type(path)

    try:
        import openpyxl
    except (ModuleNotFoundError, ImportError) as e:
        raise Exception("You must install openpyxl package to use this method")

    data = pd.read_excel(path, sheet_name=None)

    data_tables = {
        name: TupList(content.to_dict(orient="records")).vapply(
            lambda v: SuperDict(v).vapply(lambda vv: format_value(vv)))
        for name, content in data.items() if name not in param_tables_names
    }

    parameters_tables = {
        t: SuperDict(read_param_table(path,
                                      t)).vapply(lambda v: format_value(v))
        for t in param_tables_names
    }

    return {**data_tables, **parameters_tables}
Exemplo n.º 3
0
    def solve_one_iteration(self, solver, used_routes, previous_value, current_round):
        if 0 < current_round <= self.limit_artificial_round + 1:
            self.generate_new_routes()
            self.artificial_quantities = dict()

        old_used_routes = pickle.loads(pickle.dumps(used_routes, -1))
        previous_routes_infos = [
            (shift["id_shift"], shift["trailer"], shift["driver"])
            for shift in self.solution.get_all_shifts()
        ]

        if current_round > 0:
            selected_routes = self.select_routes(self.nb_routes)
            used_routes = SuperDict({**used_routes, **selected_routes})
            self.initialize_parameters(used_routes)

        model = self.new_model(
            used_routes,
            previous_routes_infos,
            current_round <= self.limit_artificial_round,
        )
        status = model.solve(solver=solver)

        if status == 1:
            self.to_solution(model, used_routes, current_round)
            if current_round > self.limit_artificial_round:
                self.check_and_save(current_round)

        if status != 1 or current_round == 0:
            used_routes = old_used_routes
            return used_routes, None

        if not (
            previous_value is None
            or pl.value(model.objective) < previous_value
            or (
                (current_round > self.limit_artificial_round)
                and (self.last_solution_round <= self.limit_artificial_round)
            )
        ):
            return old_used_routes, previous_value

        keep = (
            self.route_var.vfilter(lambda v: pl.value(v) > 0.5)
            .keys_tl()
            .take(0)
            .to_dict(None)
            .vapply(lambda v: True)
        )

        used_routes = {
            r: route for r, route in used_routes.items() if keep.get(r, False)
        }

        if current_round > self.limit_artificial_round:
            previous_value = pl.value(model.objective)
        self.last_solution_round = current_round
        return used_routes, previous_value
Exemplo n.º 4
0
def sources_to_jsonschema(sources_data):

    allowedTrailers = [
        SuperDict(id_location=key, id_trailer=id_trailer) for key, trailers in
        sources_data.get_property("allowedTrailers").items()
        for id_trailer in trailers
    ]

    sources = drop_props_get_values(sources_data, ["allowedTrailers"])
    return SuperDict(sources=sources, allowedTrailers=allowedTrailers)
Exemplo n.º 5
0
def customers_to_jsonschema(customers_data: SuperDict):
    customersTimeWindows = [
        SuperDict(id_customer=key, **tw) for key, time_windows in
        customers_data.get_property("timewindows").items()
        for tw in time_windows
    ]

    orders = [
        SuperDict(id_customer=key, **order)
        for key, orders in customers_data.get_property("orders").items()
        for order in orders
    ]

    forecasts = [
        SuperDict(id_customer=key, time=time, forecast=forecast)
        for key, forecasts in customers_data.get_property("Forecast").items()
        for time, forecast in enumerate(forecasts) if forecast > 0
    ]

    allowedTrailers = [
        SuperDict(id_location=key, id_trailer=id_trailer) for key, trailers in
        customers_data.get_property("allowedTrailers").items()
        for id_trailer in trailers
    ]
    customers = drop_props_get_values(
        customers_data,
        ["timewindows", "Forecast", "allowedTrailers", "orders"])
    return SuperDict(
        customers=customers,
        customersTimeWindows=customersTimeWindows,
        orders=orders,
        forecasts=forecasts,
        allowedTrailers=allowedTrailers,
    )
Exemplo n.º 6
0
    def __init__(self,
                 path,
                 output_path=None,
                 ignore_files=None,
                 leave_bases=False):

        self.path = path
        self.tmp_path = os.path.join(os.getcwd(), "tmp_files")
        self.output_path = output_path or "./output_schema.json"
        self.ignore_files = ignore_files or []
        self.leave_bases = leave_bases or False
        self.parents = dict()
        self.data = SuperDict()
        self.model_table = dict()
        self.table_model = dict()
Exemplo n.º 7
0
 def matrix_to_dict(matrix, key, func):
     matrix = TupList(matrix).vapply(lambda v: v[key])
     result = SuperDict()
     for L1, row in enumerate(matrix):
         for L2, col in enumerate(row):
             result[L1, L2] = func(col)
     return result
Exemplo n.º 8
0
def index_list(table, index, _list):
    """
    indexes the table by index and returns a dictionary with _list keys
    """
    return (TupList(table).to_dict(result_col=_list, indices=[
        index
    ]).vapply(lambda v: v.vapply(lambda vv: SuperDict(zip(_list, vv)))))
Exemplo n.º 9
0
    def from_dict(cls, data_dict):

        # main tables
        trailers = _index(data_dict["trailers"])
        drivers = get_drivers(data_dict)
        customers = get_customers(data_dict)
        sources = get_sources(data_dict)

        # dist and time matrices
        matrices = {(el["L1"], el["L2"]): el for el in data_dict["matrices"]}

        data_out = SuperDict(
            trailers=trailers,
            drivers=drivers,
            customers=customers,
            sources=sources,
            matrices=matrices,
            coordinates=data_dict.get("coordinates", [])
        )

        # other parameters
        for param in ["unit", "horizon"]:
            data_out[param] = data_dict["parameters"][param]

        data_out["bases"] = data_dict["bases"][0]
        return cls(data_out)
Exemplo n.º 10
0
 def inherit(self):
     all_classes = set(self.parents.keys())
     not_treated = set(all_classes)
     treated = {"db.Model"}
     while not_treated:
         for model in not_treated:
             parent = self.parents[model]
             if parent is None:
                 treated.add(model)
                 continue
             if parent not in treated:
                 continue
             treated.add(model)
             if parent == "db.Model":
                 continue
             table_name = self.model_table[model]
             parent_props = self.data[
                 self.model_table[parent]]["items"]["properties"]
             parent_requirements = self.data[
                 self.model_table[parent]]["items"]["required"]
             self.data[table_name]["items"]["properties"] = SuperDict(
                 **parent_props,
                 **self.data[table_name]["items"]["properties"])
             self.data[table_name]["items"][
                 "required"] += parent_requirements
         not_treated -= treated
     if not self.leave_bases:
         self.data = self.data.vfilter(lambda v: not v.get("remove", False))
Exemplo n.º 11
0
 def check_solution(self):
     return SuperDict({
         **self.check_shifts(),
         **self.check_sites(),
         **self.check_resources(),
         **self.check_service_quality(),
     }).vfilter(lambda v: len(v))
Exemplo n.º 12
0
    def solve(self, options: dict) -> dict:

        model = pl.LpProblem("rostering", pl.LpMaximize)
        # Variables:
        self.create_variables()
        # Constraints:
        model = self.create_constraints(model)
        # print(model)

        # Solver and solve
        mat_solver = pl.PULP_CBC_CMD(
            gapRel=0.001,
            timeLimit=options.get("timeLimit", 240),
            msg=options.get("msg", False),
        )
        status = model.solve(mat_solver)

        # Check status
        if model.sol_status not in [pl.LpSolutionIntegerFeasible, pl.LpSolutionOptimal]:
            return dict(status=status, status_sol=SOLUTION_STATUS_INFEASIBLE)

        work_assignments = (
            self.works.vfilter(lambda v: pl.value(v))
            .keys_tl()
            .vapply(lambda v: dict(id_employee=v[1], time_slot=v[0]))
        )

        self.solution = Solution.from_dict(SuperDict(works=work_assignments))

        return dict(status=status, status_sol=SOLUTION_STATUS_FEASIBLE)
Exemplo n.º 13
0
    def check_qs_02(self):
        """
        returns {location: nb_run_outs, ... } for locations experiencing runouts
        """
        check = SuperDict()
        nb_run_outs = 0
        site_inventories = self.calculate_inventories()

        for site in site_inventories.keys():
            site_inventory = site_inventories[site]
            nb_inventory_run_out = 0
            if not site_inventories[site]:
                continue
            if site > self.nb_customers + self.nb_sources + 1:
                continue
            if self.is_customer(site):
                customer = self.instance.get_customer(site)
                nb_inventory_run_out += sum(
                    1 for i in range(self.horizon)
                    if round(site_inventory["tank_quantity"][i], 2) < 0
                    if customer["callIn"] == 0)
            nb_run_outs += nb_inventory_run_out
            if nb_inventory_run_out != 0:
                check[site] = nb_inventory_run_out
        return check
Exemplo n.º 14
0
 def get_aux_info_shift(self):
     """
     Returns a dictionary containing information about each shift of self.solution,
         like : the ending time of the shift (in minutes), the inventory of the trailer at the end of the shift,
         the total duration of the shift and its driving duration
         For example: {2: {'arrival_time': 367, 'final_inventory': 1760, 'duration': 187, 'driving_duration': 160},
                       3: {'arrival_time': 512, 'final_inventory': 950, 'duration': 203, 'driving_duration': 180} }
     """
     shifts = self.solution.get_shifts_dict()
     result = SuperDict()
     for id_shift, shift in shifts.items():
         cumulated_driving_time = 0
         for s, (stop, next_stop) in enumerate(
                 zip(shift['route'], shift['route'][1:])):
             stop["cumulated_driving_time"] = cumulated_driving_time
             cumulated_driving_time += self.instance.get_time_between(
                 stop["location"],
                 next_stop["location"],
             )
         shift["route"][-1][
             "cumulated_driving_time"] = cumulated_driving_time
         result[id_shift] = dict(
             arrival_time=shift["route"][-1]["arrival"],
             final_inventory=shift["initial_quantity"] +
             sum([step["quantity"] for step in shift["route"]]),
             duration=shift["route"][-1]["arrival"] -
             shift["departure_time"],
             driving_duration=sum(
                 self.instance.get_time_between(
                     stop["location"], next_stop["location"]) for stop,
                 next_stop in zip(shift["route"], shift["route"][1:])))
     return result
Exemplo n.º 15
0
    def sub_check_qs_03(self, shift, id_shift):
        """
        returns {(shift_id, location): 1, ... } for deliveries not related to an order to callIn customer
        """
        check = SuperDict()

        for operation in shift["route"][:-1]:
            location = operation["location"]
            if not self.is_valid_location(location):
                continue
            if not self.is_customer(location):
                continue
            customer = self.instance.get_customer(location)
            if customer["callIn"] == 0 or not customer["orders"]:
                continue
            tw_found = False
            ind_tw = 0
            while ind_tw < len(customer["orders"]) and not tw_found:
                order = customer["order"][ind_tw]
                if order["earliestTime"] <= operation["arrival"] <= order[
                        "latestTime"]:
                    tw_found = True
                ind_tw += 1
            if not tw_found:
                check[(id_shift, location)] = 1
        return check
Exemplo n.º 16
0
def drivers_to_jsonschema(drivers_data: SuperDict):
    driversTimeWindows = [
        dict(id_driver=key, **tw) for key, time_windows in
        drivers_data.get_property("timewindows").items() for tw in time_windows
    ]

    driversTrailers = [
        SuperDict(id_driver=key, id_trailer=trailer)
        for key, trailers in drivers_data.get_property("trailer").items()
        for trailer in trailers
    ]
    drivers = drop_props_get_values(drivers_data, ["trailer", "timewindows"])
    return SuperDict(
        drivers=drivers,
        driversTrailers=driversTrailers,
        driversTimeWindows=driversTimeWindows,
    )
Exemplo n.º 17
0
    def from_dict(cls, data: dict) -> "Solution":
        data_p = {
            el: {(v["id_employee"], v["time_slot"]): v
                 for v in data[el]}
            for el in ["works"]
        }

        return cls(SuperDict(data_p))
Exemplo n.º 18
0
    def __init__(self, data: dict):
        super().__init__(data)

        # Stores a list of the starting date of each week ordered
        self.weeks = TupList()

        # First object stores a list of the dates ordered,
        # the second the properties for each date.
        self.dates = TupList()
        self.dates_properties = SuperDict()

        # First object stores a list of the time slots ordered,
        # the second the properties for each one.
        self.time_slots = TupList()
        self.time_slots_properties = SuperDict()

        self.cache_properties()
Exemplo n.º 19
0
 def check_availability(self):
     availability_dict = self.instance.get_availability()
     purchases_dict = self.solution.get_amount_supplied().kfilter(
         lambda k: k[0] in self.instance.get_suppliers()
     )
     check_dict = SuperDict.from_dict(
         {k: availability_dict[k] - purchases_dict[k] for k in availability_dict}
     )
     return check_dict.vfilter(lambda v: v < 0)
Exemplo n.º 20
0
    def from_file(cls, path):
        data = SuperDict(suppliers=dict(sheet_name="suppliers_L1",
                                        index_col=[0, 1, 2]),
                         products=dict(sheet_name="products",
                                       index_col=[0, 1, 2]),
                         clients=dict(sheet_name="clients", index_col=[0, 1]),
                         warehouses=dict(sheet_name="warehouses",
                                         index_col=[0, 1, 2, 3]),
                         distances=dict(sheet_name="distances",
                                        index_col=[0, 1, 2]),
                         restricted_flows=dict(sheet_name="not_allowed_flows",
                                               index_col=[0, 1]))

        def read_table(**kwargs):
            return pd.read_excel(filename=path, header=0,
                                 **kwargs).index.values.tolist()

        return cls(data.vapply(lambda v: read_table(**v)))
Exemplo n.º 21
0
 def check_shift_03(self, shift, id_shift):
     """
     returns {"wrong_index": {(id_shift, id_location): 1, ... } for non existent locations,
              "setup_time":  {(id_shift, id_location): 1, ... } for operation that does not respect setup time }
     """
     check = SuperDict(wrong_index=SuperDict(), setup_time=SuperDict())
     id_operation = 1
     for operation in shift["route"][:-1]:
         if not self.is_valid_location(operation["location"]):
             check["wrong_index"][(id_shift, id_operation)] = 1
             continue
         location = operation["location"]
         if location > 0:
             setup_time = self.instance.get_location_property(
                 location, "setupTime")
             if operation["departure"] < operation["arrival"] + setup_time:
                 check["setup_time"][(id_shift, location)] = 1
         id_operation += 1
     return check
    def setUp(self):
        super().setUp()

        self.full_inst_path = self._get_path("./data/instance.json")
        self.full_inst = SuperDict.from_dict(
            self.import_schema(self.full_inst_path))
        # Removing parameter tables
        self.full_inst["properties"] = self.full_inst["properties"].vfilter(
            lambda v: v["type"] == "array")
        self.one_tab_inst_path = self._get_path("./data/one_table.json")
        self.one_tab_inst = SuperDict.from_dict(
            self.import_schema(self.one_tab_inst_path))
        self.app_name = "test"
        self.second_app_name = "test_sec"
        self.default_output_path = self._get_path("./data/output")
        self.other_output_path = self._get_path("./data/output_path")
        self.last_path = self.default_output_path
        self.all_methods = TupList(
            ["getOne", "getAll", "deleteOne", "deleteAll", "update", "post"])
Exemplo n.º 23
0
 def check_solution(self, *args, **kwargs) -> dict:
     return SuperDict(
         availability=self.check_availability(),
         restricted_flows=self.check_restricted_flows(),
         demand=self.check_demand(),
         second_doses=self.check_second_dose(),
         warehouse_capacities=self.check_warehouse_capacity(),
         consistency_warehouses=self.check_consistency_warehouses(),
         consistency_suppliers=self.check_consistency_suppliers(),
     )
Exemplo n.º 24
0
    def from_dict(cls, data_dict):

        rows = SuperDict(
            {
                (el["id_shift"], el["position"]): SuperDict(el)
                for el in data_dict["details_shifts"]
            }
        )
        details = rows.to_dictdict().vapply(
            lambda v: v.values_tl().sorted(key=lambda x: x["position"])
        )

        data = {
            shift["id_shift"]: SuperDict(shift) for shift in data_dict["info_shifts"]
        }
        for shift in data:
            data[shift]["route"] = details[shift]

        return cls(data)
Exemplo n.º 25
0
    def solve(self, options: dict):
        distance = (
            self.instance.get_arcs()
            .to_dict(result_col=["w"], indices=["n1", "n2"], is_list=False)
            .kfilter(lambda k: k[0] != k[1])
        )
        model = cp_model.CpModel()
        create_literal = lambda i, j: model.NewBoolVar("%i follows %i" % (j, i))
        literals = distance.kapply(lambda k: create_literal(*k))
        arcs = literals.to_tuplist()
        model.AddCircuit(arcs)

        model.Minimize(sum((literals * distance).values()))
        solver = cp_model.CpSolver()
        if options.get("msg", False):
            solver.parameters.log_search_progress = True
        # To benefit from the linearization of the circuit constraint.
        solver.parameters.linearization_level = 2
        solver.parameters.max_time_in_seconds = options.get("timeLimit", 10)
        if "threads" in options:
            solver.parameters.num_search_workers = options["threads"]

        status = solver.Solve(model)
        if options.get("msg", False):
            print(solver.ResponseStats())

        status_conv = {
            cp_model.OPTIMAL: STATUS_OPTIMAL,
            cp_model.INFEASIBLE: STATUS_INFEASIBLE,
            cp_model.UNKNOWN: STATUS_UNDEFINED,
            cp_model.MODEL_INVALID: STATUS_UNDEFINED,
        }
        if status not in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
            return dict(
                status=status_conv.get(status), status_sol=SOLUTION_STATUS_INFEASIBLE
            )
        next = (
            literals.vapply(solver.BooleanValue)
            .vfilter(lambda v: v)
            .keys_tl()
            .to_dict(1, is_list=False)
        )
        first = next.keys_tl(0)
        current_node = first
        solution = TupList([first])
        while True:
            current_node = next[current_node]
            if current_node == first:
                break
            solution.append(current_node)
        nodes = solution.kvapply(lambda k, v: SuperDict(pos=k, node=v))
        self.solution = Solution(dict(route=nodes))

        return dict(status=status_conv.get(status), status_sol=SOLUTION_STATUS_FEASIBLE)
Exemplo n.º 26
0
 def get_demand(self) -> SuperDict:
     """
     Returns a SuperDict indexed by the time slot (string) and the demand as value
     For example: {"2021-09-06T07:00": 10, "2021-09-06T08:00": 15, ...}
     """
     return SuperDict(
         {
             self._get_time_slot_string(ts): self._filter_demand(ts)
             for ts in self.time_slots
         }
     )
Exemplo n.º 27
0
 def get_total_number_cut_products(self) -> SuperDict:
     """
     Returns a SuperDict the products as keys and the total number of cut products as values.
     For example, {'pr1': 600, 'pr2': 500, ...}
     """
     number_patterns = self.get_number_bars_patterns()
     number_products_per_pattern = self.get_number_products_per_pattern()
     total_number_cut_products = SuperDict()
     for (bar, pattern, product) in number_products_per_pattern.keys_tl():
         if product not in total_number_cut_products.keys():
             total_number_cut_products[product] = (
                 number_products_per_pattern[(bar, pattern, product)]
                 * number_patterns[(bar, pattern)]
             )
         else:
             total_number_cut_products[product] += (
                 number_products_per_pattern[(bar, pattern, product)]
                 * number_patterns[(bar, pattern)]
             )
     return total_number_cut_products
Exemplo n.º 28
0
 def check_shift_05(self, shift, id_shift, trailer):
     """
     returns {(shift_id, location): 1, ... } for incompatible shift-location combination
     """
     check = SuperDict()
     for operation in shift["route"][:-1]:
         location = operation["location"]
         if self.is_customer_or_source(location):
             if trailer not in self.instance.get_location_property(
                     location, "allowedTrailers"):
                 check[(id_shift, location)] = 1
     return check
Exemplo n.º 29
0
    def create_variables(self):

        self.works = pl.LpVariable.dicts(
            "works",
            self.employee_ts_availability,
            lowBound=0,
            upBound=1,
            cat=pl.LpBinary,
        )

        self.works = SuperDict(self.works)

        self.starts = pl.LpVariable.dicts(
            "starts",
            self.employee_ts_availability,
            lowBound=0,
            upBound=1,
            cat=pl.LpBinary,
        )

        self.starts = SuperDict(self.starts)
Exemplo n.º 30
0
 def check_shift_11(self, shift, id_shift):
     """
     returns {(shift_id, location): quantity, ... } for operation with wrong sign
     """
     check = SuperDict()
     for i in range(1, len(shift["route"]) + 1):
         operation = shift["route"][i - 1]
         location = operation["location"]
         if self.is_source(location) and operation["quantity"] < 0:
             check[(id_shift, location)] = operation["quantity"]
         elif self.is_customer(location) and operation["quantity"] > 0:
             check[(id_shift, location)] = operation["quantity"]
     return check