Ejemplo n.º 1
0
 def reset(self):
     units = filter(None, [self.consumer, self.manufacturing, self.seller])
     for unit in units:
         unit.reset()
     self.economy = ProductUnit.Economy(
         BalanceSheet(self.initial_balance, 0),
         BalanceSheet(self.initial_balance, 0))
Ejemplo n.º 2
0
 def reset(self):
     units = filter(None, [self.storage, self.distribution])
     for unit in units:
         unit.reset()
     self.economy = FacilityCell.Economy(
         BalanceSheet(self.initial_balance, 0),
         BalanceSheet(self.initial_balance, 0))
     # sample inventory in stock randomly
     for sku in self.sku_in_stock:
         sku.reset()
         init_stock = np.random.randint(sku.sku_info.get('init_stock', 100))
         self.storage.try_add_units({sku.sku_info['sku_name']: init_stock})
Ejemplo n.º 3
0
 def step_balance_sheet(self, units_sold, unit_price, out_stock_demand,
                        backlog_ratio):
     # (销售利润,缺货损失)
     balance = BalanceSheet(
         self.profit(units_sold, unit_price),
         -self.profit(out_stock_demand, unit_price) * backlog_ratio)
     # balance = BalanceSheet(self.profit(units_sold, unit_price), 0)
     return balance
Ejemplo n.º 4
0
 def __init__(self, x, y, world, config, economy_config):
     super(FacilityCell, self).__init__(x, y)
     self.id_num = world.generate_id()
     self.idx_in_config = None
     self.id = f"{self.__class__.__name__}_{self.id_num}"
     self.world = world
     self.initial_balance = economy_config.initial_balance
     self.economy = FacilityCell.Economy(
         BalanceSheet(self.initial_balance, 0),
         BalanceSheet(self.initial_balance, 0))
     self.storage = None
     self.distribution = None
     self.consumer = None
     self.seller = None
     self.sku_in_stock = []
     self.facility_short_name = None  # for rendering
     self.facility_info = None
     self.step_reward = 0
Ejemplo n.º 5
0
 def __init__(self, facility, config, economy_config):
     self.initial_balance = economy_config.initial_balance
     self.economy = ProductUnit.Economy(
         BalanceSheet(self.initial_balance, 0),
         BalanceSheet(self.initial_balance, 0))
     self.facility = facility
     self.id_num = facility.world.generate_id()
     self.id = f"{self.__class__.__name__}_{self.id_num}"
     self.idx_in_config = None
     self.distribution = None
     self.storage = None
     self.consumer = None
     self.sku_info = None
     self.manufacturing = None
     self.seller = None
     self.bom = config.bill_of_materials
     self.downstream_skus = []
     self.unit_price = 0
     self.step_reward = 0
Ejemplo n.º 6
0
 def act(self, control):
     units = filter(None, [self.consumer, self.manufacturing, self.seller])
     # print(type(self.seller))
     balance_rewards = [u.act(control) for u in units]
     balance_sheets = [b[0] for b in balance_rewards]
     rewards = [r[1] for r in balance_rewards]
     product_id = self.sku_info['sku_name']
     if self.storage is not None:
         storage_reward = -self.storage.stock_levels[
             product_id] * self.storage.economy.unit_storage_cost
     else:
         storage_reward = 0
     storage_balance = BalanceSheet(0, storage_reward)
     if self.distribution is not None:
         checkin_order = self.distribution.checkin_order[product_id]
         transportation_cost = self.distribution.transportation_cost[
             product_id]
         delay_order_penalty = self.distribution.delay_order_penalty[
             product_id]
         distribution_reward = -(transportation_cost + delay_order_penalty)
         self.distribution.checkin_order[product_id] = 0
         self.distribution.transportation_cost[product_id] = 0
         self.distribution.delay_order_penalty[product_id] = 0
         distribution_balance = BalanceSheet(checkin_order,
                                             distribution_reward)
     else:
         distribution_reward = 0
         distribution_balance = BalanceSheet()
     self.economy.deposit(balance_sheets +
                          [storage_balance, distribution_balance])
     # pop up rewards of downstreaming SKUs
     downstream_skus_reward = 0
     for sku in self.downstream_skus:
         downstream_skus_reward += sku.step_reward
     self.step_reward = sum(
         rewards +
         [storage_reward, distribution_reward, downstream_skus_reward])
     # reward can be different from balance
     return self.economy.step_balance, self.step_reward
Ejemplo n.º 7
0
 def act(self, control):
     # if control is not None:
     # self.economy.unit_price = control.unit_price    # update unit price
     step_balance = BalanceSheet()
     for vechicle in self.fleet:
         if len(self.order_queue) > 0 and not vechicle.is_enroute():
             order = self.order_queue.popleft()
             vechicle.schedule(self.facility.world, order.destination,
                               order.product_id, order.quantity, order.vlt)
             transportation_balance, reward = vechicle.act(None)
             self.transportation_cost[order.product_id] += abs(reward)
         else:
             transportation_balance, reward = vechicle.act(None)
             self.transportation_cost[vechicle.product_id] += abs(reward)
         step_balance += transportation_balance
     delay_order_penalty = self.facility.facility_info.get(
         'delay_order_penalty', 0)
     for order in self.order_queue:
         self.delay_order_penalty[order.product_id] += delay_order_penalty
     # Distribution balance and reward
     return step_balance, 0
Ejemplo n.º 8
0
    def act(self, control):
        if self.step > 0:
            if self.location_pointer == 0 and self.payload == 0:
                self.try_loading(self.requested_quantity)

            if self.payload > 0:  # will stay at the source until loaded or timeout
                self.cur_time = 0  # reset cur_time
                if self.location_pointer < len(self.path) - 1:
                    self.location_pointer = min(
                        len(self.path) - 1, self.location_pointer + self.step)
                else:
                    self.step = -self.step  # arrived to the destination
            if self.cur_time > self.patient:
                self.destination.consumer._update_open_orders(
                    self.sku.id, self.product_id, -self.requested_quantity)
                self.cur_time = 0
                self.location_pointer = 0
                self.step = 0  # arrived back to the source
                self.destination = None
                return BalanceSheet(0, -self.sku.sku_info.get(
                    'penalty', 0)), -self.sku.sku_info.get('penalty', 0)

        if self.step < 0:
            if self.location_pointer == len(
                    self.path) - 1 and self.payload > 0:
                self.try_unloading()

            if self.payload == 0:  # will stay at the destination until unloaded
                if self.location_pointer > 0:
                    self.location_pointer = max(
                        0, self.location_pointer + self.step)
                else:
                    self.step = 0  # arrived back to the source
                    self.destination = None

        return self.economy.step_balance_sheet(self), self.economy.step_reward(
            self)
Ejemplo n.º 9
0
 def act(self, control):
     units_produced = 0
     sku_num = len(self.facility.facility.sku_in_stock)
     unit_num_upper_bound = self.facility.storage.max_capacity // sku_num
     if control is not None:
         for _ in range(control.production_rate):
             # check we have enough storage space for the output lot
             if (self.facility.storage.available_capacity() >=
                     self.facility.bom.output_lot_size -
                     self.facility.bom.input_units_per_lot()
                     and self.facility.storage.stock_levels[
                         self.facility.bom.output_product_id] <
                     unit_num_upper_bound):
                 # check we have enough input materials
                 if self.facility.storage.try_take_units(
                         self.facility.bom.inputs):
                     self.facility.storage.stock_levels[
                         self.facility.bom.
                         output_product_id] += self.facility.bom.output_lot_size
                     units_produced += self.facility.bom.output_lot_size
     self.manufacturing_cost = self.facility.sku_info[
         'cost'] * units_produced
     return BalanceSheet(0,
                         -self.manufacturing_cost), -self.manufacturing_cost
Ejemplo n.º 10
0
 def global_balance(self) -> BalanceSheet:
     total_balance = BalanceSheet()
     for facility in self.world.facilities:
         if isinstance(facility, FacilityCell):
             total_balance += facility.economy.total_balance
     return total_balance
Ejemplo n.º 11
0
    def act(self, control):
        if control is None or control.consumer_product_id is None or control.consumer_quantity <= 0:
            return BalanceSheet(), 0
        if self.sources is None:
            return BalanceSheet(), 0

        source_obj = self.sources[control.consumer_source_id]
        # sku_cost = source_obj.sku_info.get('cost', 0)
        # order_cost =  - self.economy.order_cost - sku_cost * control.consumer_quantity
        # TODO: no enough money, only for RetailerCell now
        # if isinstance(self.facility.facility, RetailerCell):
        #     # print(self.facility.id, self.facility.facility.economy.total_balance.total(), order_cost)
        #     if self.facility.facility.economy.total_balance.total() < abs(order_cost):
        #         return BalanceSheet()

        # source_service_level = source_obj.sku_info.get('service_level', 1.0)
        # if rnd.random() >= source_service_level:
        # return BalanceSheet(source_obj.sku_info.get('penalty', 0), 0)

        self._update_open_orders(source_obj.id, control.consumer_product_id,
                                 control.consumer_quantity)
        sku_price = self.facility.get_selling_price()
        sku_cost = self.facility.sku_info['cost']
        # simple demand forecast algorithm, AVG(latest sales in 14 days)
        # TODO: More advanced forecast algorithm
        sale_mean = max(1.0, self.facility.get_sale_mean())
        order = DistributionUnit.Order(self.facility,
                                       control.consumer_product_id,
                                       control.consumer_quantity,
                                       control.consumer_vlt)
        # Get inventory in stock and transit
        in_transit_orders = sum(self.open_orders.values(), Counter())
        sku_in_stock_and_transit = (
            self.facility.storage.stock_levels[control.consumer_product_id] +
            in_transit_orders[control.consumer_product_id])
        if self.facility.distribution is not None:
            inventory_to_be_distributed = self.facility.distribution.get_pending_order(
            )[control.consumer_product_id]
            sku_in_stock_and_transit -= inventory_to_be_distributed
        # Expect days to clear existing stock
        expect_sale_days = (sku_in_stock_and_transit +
                            control.consumer_quantity / 2) / sale_mean
        holding_cost = self.facility.storage.economy.unit_storage_cost
        # expect_holding_cost = (sku_in_stock_and_transit + control.consumer_quantity) * holding_cost / 2
        expect_holding_cost = control.consumer_quantity * expect_sale_days * holding_cost
        # place the order
        order_product_cost = source_obj.distribution.place_order(order)
        self._update_latest_consumptions(order.quantity)
        self.economy.total_units_purchased += control.consumer_quantity
        order_cost = self.facility.facility.facility_info['order_cost']

        # for SKU in warehouse, take 10% of its cost as profit
        is_retailer = isinstance(self.facility, SKUStoreUnit)

        order_profit = (sku_price - sku_cost) * order.quantity

        balance = BalanceSheet(0, -order_cost - order_product_cost)
        self.products_received = 0
        self.lost_product_value = 0
        # reward is discounted according to expected days before the current order can make profits
        echelon = -1
        if isinstance(self.facility, SKUWarehouseUnit):
            echelon = self.facility.facility.echelon_level
        # reward_discount = Utils.get_reward_discount(expect_sale_days, is_retailer, echelon)
        reward_discount = 1
        reward = -order_cost - order_product_cost - expect_holding_cost + reward_discount * order_profit
        return balance, reward
Ejemplo n.º 12
0
 def step_balance_sheet(self, units_produced):
     return BalanceSheet(0, self.cost(units_produced))
Ejemplo n.º 13
0
 def step_balance_sheet(self, transport):
     return BalanceSheet(0,
                         -transport.payload * self.unit_transport_cost)
Ejemplo n.º 14
0
 def step_balance_sheet(self, storage):
     return BalanceSheet(
         0, -storage.used_capacity() * self.unit_storage_cost)